Departments


We Have Mail


Letters to the editor may be sent via email to cujed@mfi.com, or via the postal service to Letters to the Editor, C/C++ Users Journal, 1601 W. 23rd St., Ste 200, Lawrence, KS 66046-2700.


Dear Sir/Madam.

During the past four months I've happened to be purchasing your magazine, and a few thoughts came to my mind. The most important ones are that you display an enormous expertise in the C/C++ languages among your writers, and that you're amazingly uncritical about the merits and developments of those same languages. For instance,

1. I'd like to hear your opinion why we need C any more at all. Of course there's lots of legacy code written in C, but I take it that the C in "C/C++" means ANSI C. This is almost a subset of C++: remove the keyword class and you've got it. Sure, there are other subtle differences, but why not push really hard for getting rid of C, and have C++ being the sole survivor? For PCs it's pretty hard to buy an ANSI C compiler that won't do C++ as well; for Unix boxes the push is needed to get to that same state.

2. Certainly, as a C programmer, I'd be dismayed from reading your magazine. It focuses almost entirely on weird ways of using classes, inheritance, templates, const, what have you. It's clear to me that the language is getting very complicated, but not clear that it's getting proportionally powerful. As an example, the need to declare the typical operator[] in a const and a non-const version, even if textually identical, is ridiculous, while a way to detect l-value vs. r-value use of the operator is really needed and absent. The need to declare all the umpteen arithmetic operators, including the assigning ones (like += from +), and having to declare them all friends, for every new (arithmetic) data type, is exorbitant. Why not instigate a competition for some simplifying concept? There are many other examples, automatic use of magic memory/garbage collection vs. optional garbage collection vs. raw-coding it all over and over again by hand is another one.

So please attack the language and invite suggestions rather than always leaning up against the latest standard. It seems that the C++ world will go to any length to avoid breaking up with C, and to have a program use another byte or cycle of hardware, at the expense of the programmer having to study programming (and your journal) forever. Maybe those old habitual thoughts should be abandoned?

For now, I'll forget about C++ and focus on something else. We need a major deluge of new simplifying concepts here. CU!

Soren Nielsen
Assistant Professor, MSIS Departmen
University of Texas at Austin
snielsen@mail.utexas.edu

PS. I have some other comments on the journal's style, like why (in the April 1997 number) your page 107 spent a whole page in very small fonts on something that (after I'd read it) turned out to be some trivial bug, already corrected. An excessive treatment of "what happens to unfreed memory," as if you wouldn't be hard pressed to find anyone who doesn't know that (but I agree, do err on the side of assumed ignorance). And Bobby Schmidt, who starts out by asking us not to write him! I don't think I ever got beyond that in his, presumably, excellent piece.

Ciao!

I don't feel it's the job of this magazine to convince the world that C is archaic, or that C++ is too complex. If enough people feel that way, the marketplace will quickly render its verdict. If not enough do, no amount of proselytizing on our part will change much. We try to write about what our readers are interested in learning, at any given moment. If we guess wrong often enough, the marketplace will render its verdict against us. That's one major difference between the commercial and academic worlds. Ciao. — pjp


Dear CUJ:

I recently undertook a project to merge our standalone version of our software with our network version. The decision to merge the two versions was made so we will only have one set of source code to maintain.

All of the code has been merged by wrapping network-specific and standalone-specific code in preprocessor directives. Since the MSVC++ documentation recommends never to edit between the //{{AFX_MSG_MAP //}}AFX_MSG_MAP block, I moved the necessary message maps out of the AFX block before I wrapped the code in preprocesor directives.

My nagging problem is the resource script. I have network-specific and standalone-specific dialogs, popups, meuitems, etc. in the resource script file. I don't know how to edit the resource script or delimit my code in a way that the code generator won't modify or trip over my changes.

Can you help me? Also, do you foresee any other problems I may have overlooked? For the record I am using MSVC++ 1.52.

Thank You,
Tim Patterson
patterst@moodys.com

My ignorance of this area is profound. Anybody? — pjp


Dear Mr. Plauger,

Thanks to Keith Boone for submitting his solution to the MI issue (see "We Have Mail," CUJ, June 1997) I referred to in "Portable Signal Handling Under UNIX" in the March 1997 issue. His solution, however, requires surgery to the class that is to be made signal aware, just as inheritance does.

Given this necessity, I think that using inheritance provides an arguably more elegant solution. As I suggested in the article, applying the Visitor pattern would provide a good alternative to using inheritance, and would minimize surgery on the existing class which is to be made signal aware, although the mechanism will need to be tweaked elsewhere.

Martin Remy
remy@acm.org


Dear Editor,

I downloaded the code to Mike Benzinger and Don Retzlaff's C/C++-to-HTML converter and compiled it on a Sun workstation running SunOS. It ran quite well. I just wanted to point out a minor correction that I had to make. I had a line of code that looked like this:

cerr << "Couldn't find " << string
     << endl;

The cpptohtm.cpp code treats single and double quotes alike. Therefore, the red color indicating a string ended after Could', and restarted after the double quotes following find.

My solution was to declare a static char quote_type that would contain the type of quote that began the string. If (inString) and (quote_type != chr), the string is not complete.

Menashe Dickman
mdickman@ml.com

Thanks for the feedback. — pjp


Editor,

Your point about the chasm between CLI (command-line interface) and WIMP (windows, icons, menus, and pointing device) is one I have ranted on extensively. I have been programming professionally for 20 years, but I recently went back to school and got an MS in CS. My thesis was on the subject that the GUI doesn't afford the power that the old CLI did. I ended up creating a proof-of-concept command language that was visually oriented; sort of like building batch files with a flow-chart editor. I created an interactive development environment (I thought that edit/compile/run or even edit/interpret failed to adhere to the WYSIWYG model) that lets you put the cursor on the step you want to execute and then you can step through that function, or run the constructed script as a single entity. Let me know if you have any interest in it. It is written in TCL and runs on Linux and Win95.

As far as CLI is concerned, you said "I really miss using keyboard arrows to flip quickly through commands typed earlier" — have you seen 4dos? I use it for DOS, but I understand that there are versions for OS/2 and NT, and it really does have nice features for command-line recall and editing, not to mention filename completion.

Brian Cooper
bcooper@novell.com


Dear Dr. Plauger,

In your Editor's Forum in the July 1997 issue of CUJ, you state, "I hate the way [Unix software tools] have proliferated over the years, while nevertheless retaining as fossils all the early design mistakes. And I really miss using keyboard arrows to flip quickly through commands typed earlier." Two things:

First, could elaborate a little on what you consider design mistakes? I'm not disagreeing, I'm just curious as to what you find particularly unfriendly in your Unix environment.

Second, I assume you're talking about NT's command line editing capabilities in the second sentence. It happens that more sophisticated shells such as tcsh and bash (enhancements of csh and sh respectively) have offered command line editing for years, with features like scroll-back, command and filename completion, even emacs-style editing commands.

Unfortunately, the big commercial Unix vendors (e.g. Sun) still ship essentially the same Bourne and C shells that have been around for almost two decades. Using cursor movement keys in these beasts will only get you a line full of garbage. (This does not help them compete with NT as it encroaches upon their market.) More user-friendly shells can be installed on commercial Unices, but this is often beyond the patience and skills of end-users and naive administrators.

On the bright side, virtually all of the free Unices ship with smarter shells as the default (Linux, assorted BSD derivatives).

Sincerely,

Jamie Guinan
guinan@xensei.com

I got quite a number of useful suggestions about where to find better shells, both for Unix and DOS. Thanks to all. Still, I think it's a comment on the times that there are so many of them. As for inherited Unix irregularities, the find and tr commands immediately spring to mind as oddballs. Commands like comm and uniq should have the same comparison keys as sort. Then there's the whole business of what to do with cr/lf and ctl-Z in DOS files. I could go on, and I probably will in some future essay, but that sampling should do for now. — pjp


Dear Editor,

On the pages of CUJ I see more and more examples of useful worker classes that need to be customized in some manner. To formulate the traditional problem:

The real world often adds the following constraints:

The traditional inheritance approach suggests that CMain becomes a derived class of CUseful and overrides a virtual function of CUseful to customize its functionality. Most recently I found this suggestion in the May '97 issue of CUJ ("A reusable directory walk class." by Chris Crabtree). It makes me uncomfortable because it leads to multiple inheritance for implementation sharing purposes and unnecessarily increases the complexity of the class hierarchy.

The traditional object composition approach suggests that CUseful delegate all its custom processing to an object of type CWorkerBase. We derive a new class CWorker from CWorkerBase and implement it so that it knows about and uses CMain to implement the custom functionality. Then we create CUseful with a reference to a CWorker. I find this approach only slightly better. We are forced to create a CWorkerBase hierarchy and we must find a way to tie CWorker to CMain. The latter task usually requires us to either make CWorker a friend of CMain (which complicates the class relationships) or to provide extra public methods in CMain. Finally, some efficiency can be lost because while compiling CUseful the optimizer cannot "see" the implementation of the worker class methods.

Depending on personal taste the previous solution can be improved or worsened by deriving CMain from CWorker. Common wisdom suggests that if CWorker only has pure virtual functions multiple (mix-in) inheritance may not be too harmful. A pure template-based approach is undesirable as CUseful is not a small class; the approach can lead to code bloat.

The best approach that I have seen so far, and the one I use for my own directory walker, is essentially a hybrid one. I use something like:

template <class T>
class CUsefulInstance<T> :
 public CUseful
{
 T& m_T;
 virtual void DoSomethingSpecial
  (PUsefulData pData)
    {m_T.ProcessUsefulData(pData);}
public:
 CUsefulInstance(T& t) :
  CUseful(), m_T(t) {}
};

The implementation is succinct and general, requires no extra hierarchies, and can be fully inlined. It only restricts CMain to implement ProcessUsefulData.

However, the design leaves something to be desired. Because the constructor of CUsefulInstance<CMain> is public, the class can be constructed outside CMain. Yet if the constructor is made private and friend class T is added to the definition of CUsefulInstance<T>, T will be able to see too much of CUseful which may be undesirable.

I believe the problem I have described is one software developers see very often. What is your analysis of the proposed approaches? I'd be delighted to know your personal recommendation.

Best regards and thanks for the great magazine!

Simeon Simeonov
Simeons@allaire.com

Whew, you don't ask much, do you? All designs have tradeoffs, as you so aptly summarize. I just pick the set of tradeoffs that best meets the problem at hand, and leave it to guys like Dan Saks and Bobby Schmidt to analyze various approaches in detail. — pjp


Dear Mr. Plauger,

In your June 1997 issue, there is an article by Puneesh Chaudhry titled "A New Trace Class" which I would like to comment on. While I agree with the need for easier debug output, I don't agree with the method given in the article. Overloading operator() for this particular class is a subversion of C++ that is ignoring what operator overloading is meant to do. That article presents a solution that encourages a bad habit.

Here's my theory, proven by years of C++ coding.

Operator overloading is meant for cases where the operator has a good meaning in the context of the code. For example, the complex class has obvious operations that should be used when certain operators such as +, -, /, and * are used. In this article, we are using operator() in a context for which the meaning is not immediately obvious. If other programmers were to look at the following code

object(value1,value2)

they could determine that this is probably some kind of constructor or function call depending on the context. It is not obvious that the presumed function would return an object of the same type for use in a chained expression. C++ provides an operator for this kind of chained operation that maintains all the type safety that the author of this article is implementing. It's called operator<<, and is what I feel would be the appropriate solution. Here's the acid test:

Give these two sections of code, without any explanation, to a competent C++ programmer and ask what the intention of the two segments are:

gObject("sendPacket=", sendPkt)
 ("recvPacket=", recvPkt)
 ("num pkts=", numPkt);

and:

gObject << "sendPacket=" << sendPkt
 << "recvPacket=" << recvPkt
 << "num pkts=" << numPkt;

Or alternatively:

gObject
 << PacketInfo("sendPacket=",sendPkt)
 << PacketInfo("recvPacket=",recvPkt)
 << PacketInfo("num pkts=", numPkt);

Which do you think is more intuitive? Which uses the given operators in a context for which they were designed? My personal feeling on usage of operator overloading is to only use it when someone else could determine the proper behavior for that operator in the context of what the class is. If it is not immediately obvious, it's time for a function that explicitly states via its namesake what is being done.

I appreciate conciseness and ease of use, but conciseness should not be extended to a complex operation, just to maintain the simple case.

C++ is a very flexible language that can either be nearly self documenting or send e-mail to Afghanistan as a result of the operation a=b+c. If you do not think carefully about the features that you are using, you abuse the power available and create a maintenance and debugging headache. Just because you can doesn't mean you should, as this article inadvertently demonstrates.

Everyone should look at the code they write as if it were going into a 100,000 line program. Using operator overloading without full thought is fine if you want to impress your friends and confuse your enemies. Issues like this are considered minor to too many people. I take it very seriously because my background is writing (solo) commercial software with 100,000+ lines of C++ code that is coherent and not about to fall apart with the next addition of another class. I routinely forget the interface to the classes I wrote four years ago, but I know that if an operator is defined for that class, it has an apparent function discernible from only the operator and the name of the class. It's said that the little things are the ones that get you, and the statement applies to C++ in spades.

Keep up the good work on the magazine, I enjoy it immensely. Every issue has something that is either an alternative way of dealing with a problem I've had, or a more efficient solution to a common problem. Keep it coming!

Paul Elliott
Software Eng.
Northwood Designs, Inc.
paul@nwdesigns.com

I basically share your aesthetic, perhaps because I too make a living at maintaining code on my own for years. I nevertheless observe that overloading operator() to implement cute notation is a sport irresistible to many C++ programmers. I've learned to be leery of anything that masquerades as a function call. — pjp


Dear Mr. Plauger,

I saw in your editorial note that you are working on a Java to C translator. This interests me. Would it not be better to write the opposite for helping to convert legacy to Java?

Ken Onweller

It certainly would. I just don't know how to do it. — pjp