Departments


We Have Mail


Dear Mr. Plauger,

I've been a C Programmer for 10 years now and have regrettably moved on to C++. The largest problem I've been having with C++ is the complexity of the language; the damn compiler does too much for you. In some cases it overrides what you've intended it to do. So I'm in full agreement that a new C proposal should keep with the long-standing spirit of C:

With these concepts in mind, I propose the following additions to Mr. Jervis proposal:

a) Constants expression are evaluated at compile time. This is the method used by C++ to evaluate constants and should be used by C. This feature is to get around this C problem:

const int CHARBIT * 8;
const int MAX_BUFSZ = 10 * CHARBIT;
char *bufarr_ptr[MAX_BUFSZ];
b) The article didn't mention inline functions. This feature should work for both function declarations and header declarations. Yes, we know it would make some work for the linker guys. But we could help by doing the following:

#ifdef _NDEBUG
#  define INLINE inline
#else
#  #define INLINE /* empty */
#endif
INLINE BOOL
   checkOverflow(const char * buf_ptr )
   {
   if (buf_ptr > bufarr_ptr) {
      return TRUE;
   }
   return FALSE;
   }
We can debug this code by simply flipping compilation flags on/off.

c) a thread-safe and reduced-error-checking standard C library. The same functionality would be used, but all the subroutines would be used as follows:

   typedef struct errorblk {
   char desc[96];
   int errno;
   char name[16]
   } errorblk_t;
...
   fh = ts_fopen(&errblk, filenm, "w+");
The nice thing about using an errorblk_t is that you can call several C library calls without checking the return code:

   fh = ts_fopen( &errblk, filenm, "w+");
   ts_fwrite( &errorblk, fh, ....
   ts_lseek( &errorblk, fh, ...
   if ( errorblk.errno != TS_OKAY ) {
      ts_perror( &errorblk );
   }
This also removes the use of errno and explicitly notifies the library creator that all ts_???? routines must be reentrant.

d) Mr. Jervis did mention inheritance and virtual functions, which I feel are key features missing from C. Unfortunately, the mechanism to define the class access hierachy is missing from the proposal. The user cannot use the protected, public, and private keywords that C++ contains when declaring a derived class. An example would be:

class base { .... }
class derived /* protected */ base { ... }
// class derived :: protected base { ... }
I don't agree with Mr. Jervis's use of the derived keyword because it's already a standard, even though his logic is correct.

e) The last thing I've alway wished C had was a method to reduce structure indirections. This is a feature that Pascal has with the with keyword. Frequently, I'm forced to create temporaries to track very long structure indirections. I've seen other programmers use #defines (really).

Respectfully,

David Dennerline
d.dennerline@bull.com

Dear Mr. Plauger,

I have just read Bob Jervis' "All is Flux" article in the October 1994 issue of CUJ. I like the ideas he presents and am in total agreement with what he says. He has, however, left one issue out which I would like to comment on. That issue is how base class virtual methods are called from child classes.

One of the powerful aspects of virtual methods is that they can be used to slightly modify the functionality of the base class. For example, a SpecialButton class may wish to distinguish itself from a normal Button class by adding an extra frame around the button drawn on the screen. To do that, it uses the capabilities of virtual methods to create its own Draw method. Rather than copy the screen drawing code in the Button class, it should be able to call the Button class's Draw method and then continue with framing the button so drawn.

This is an important capability of virtual functions and I expect that it wasn't explicitly written in the article because it logically followed. But there are issues surrounding the syntax of how to call overridden methods. In C++ you can call the overridden method by prefixing it with the parent class name. In my example, the code would look something like this:

class Button {
public:
   virtual void Draw(void);
   ...
   };
class SpecialButton : public Button {
public:
   virtual void Draw(void);
   ...
   };
SpecialButton::Draw() {
   Button::Draw();
   ... // draw frame around button
   }
While in this example this makes sense, it can become confusing in larger hierarchies. For example:

class Button {
public:
   virtual void Draw(void);
   ...
   };
class StateButton public Button {
   ...    // doesn't override Draw
};
class SpecialButton : public StateButton {
public:
   virtual void Draw(void);
   ...
   };
SpecialButton::Draw() {
   StateButton::Draw();
   ... // draw frame around button
   }
In this case, a second class is added, StateButton, which doesn't override the Draw method. In C++, the SpecialButton::Draw method can explicitly call the Button::Draw method, but this bypasses any virtual overrides which the StateButton class may have defined. Therefore, it is appropriate to call the StateButton::Draw method, even though it does not declare one! While the reason for using the StateButton::Draw syntax rather than the Button::Draw one can be explained, it is confusing for programmers just learning C++.

Now, leaving C++ and its complexity behind, look at the equivalent C with Classes code for the first code snippet.

class Button {
public:
   virtual void Draw(void);
   ...
   };
class SpecialButton inherit Button {
public:
   virtual void Draw(void);
   ...
   };
SpecialButton::Draw() {
   Button::Draw();
   ... // draw frame around button
   }
This syntax still has the same level of confusion inherent in it as C++.

To refresh our memories, I don't believe that C with Classes should not provide a similar capability. As I said, the ability to call overridden virtual methods provides most of the power of polymorphism.

Instead of the class::method syntax, I would like to propose a syntax I first ran into in Object Pascal. (Don't throw it out just because it has Pascal roots.) The use of the keyword inherited allows for calling the immediately overridden virtual method. In this case, the code for the SpecialButton::Draw would look like:

SpecialButton::Draw() {
   inherited Draw();
   ... // draw frame around button
   }
Or some similar syntax. This makes it clear that the programmer knows that the override function is being called, ties the method of calling such a function in with the inherit keyword in the class declaration, and eliminates the confusion about which class name to prefix a overridden method with.

There are some implications to what I just proposed. First, this syntax will only work because C with Classes implements single inheritance. Second, a virtual method can only call the full chain of overridden methods. (I am not sure if this is true, but in C++ it appears that you can bypass a level of virtual functions by using an older class in the explicit class-name::method-name syntax.)

For what it's worth, I feel that this method of calling overridden virtual functions fits with C's feel better than the C++ syntax.

Steven Kienle
sckienle@pwinet.upj.com

P.S. I feel compelled to remind all programmers that foobar is not the correct spelling of the word. Fubar is, as it is an acronym for "Fouled Up Beyond All Recognition." [Fouled is a euphemism — pjp]

Your concern is noted, along with many others. I repeat for emphasis that the goal of revising Standard C is to incorporate existing practice where it makes sense to do so, not to invent. — pjp

Dear Mr. Plauger,

I completely agree with Bob Jervis's proposal on the evolution of C, and with your comment.

I have been using C before, and I am using C++ now. Well, I must admit that I am actually only using a subset of C++, and should prefer to work with a less powerful but simpler, more reliable, and more predictable compiler.

Now, having read Jervis's article, I believe that the proposed updated C is the language I need, and hope that we shall be able to use such a language as soon as possible.

Please, keep us informed about it. Thank you.

Sincerely,

Emilio Morello
Via Cantore 79
10095 Grugliasco (To)
Italy

Dear Sirs;

Re: C Standard Effort "All is Flux"

There are many "features" within the C language that need improving. I believe that C was in danger of death when the C committee met to establish the standard for C in 1985. It was nearly impossible to successfully write a production program of one million lines in C. The lead time between versions grew toward two years typically. Projects got dropped. Doom and gloom were the norms. Weird coding conventions like the "Hungarian" got invented and adopted. Bugs proliferated and "Lints" multiplied. Then the committee adopted function prototypes and type checking. The committee adopted additional stern measures and C survived.

Now we should complete the typing of the C language. Make the old K&R style functions illegal. Remove the int default type specifier. Make the language fully typed. Make it possible for the compiler to kill the bugs. Too many programmers are ignoring the warnings generated by the compiler. It drives me to tears to read some code.

Avast! I still see many compilers making new functions from improperly constructed casts. Casts! Aghast! Casts are currently the most abused and error causing feature of C. The C++ committee has seen the same defect. I say adopt the identical solution. Make casts explicit so that one can read them correctly six months after writing them. Make them so that the compiler can identify errors of syntax, instead of labeling them as casts.

C has drawn to it programmers from other languages. I see published code that looks like COBOL! I won't mention the name of an MS Windows guru whose code examples begin with a long list of global function prototypes and defines. Not to mention that this style means flipping pages of code to find the prototypes. (Yea, some of us have to read this code stuff.) Localize these functions to some blocks of code. Put them into libraries or headers and let us use the "namespaces" feature of C++, or come up with a better solution!

Then, also, the compiler sometimes calls the wrong function. It is the name scope role biting again. Or should we say, the lack of enough rules. Namespaces is the feature that I am calling for in this complaint. We can make purchased libraries easier to use. With this scope addition, we need type safe linking. Since many linkers fail to complain of external functions defined differently in two or more translation units, the whole portable C development environment needs deliberation. It would help to separate linkage and memory allocation identifiers so that keywords like static do not have two different meanings. At least, we can adopt the C++ const function ideal to replace the preprocessor #define. It surely would make for easier reading of source code. With this const comes its anti, the mutable. I know that the powers that be require the C++ committee to give to the C committee a listing of incompatibilities. Many above ideals can reduce this list without breaking existing code. (And what it does break, that code needs fixing even now.) The C committee can see if adopting others won't break existing code.

These above ideals all reduce coding errors (unplanned "features"). Compiler writers can carry out the above in C without making C be like C++. Speaking of C++, we don't need another C++ language. If we add classes to C, we change it into a caricature of C++. As most C++ compilers come with either a C compiler included or a compatibility mode built-in, augmenting C with C++ object supporting features wastes our money. Indubitably, IBM and Microsoft and others have already invented pseudo-object mechanisms using C with their SOM and COM and CORBA technology. The act of adding classes to C would not make C classes usable with this existing technology. C with classes is C++. This kindly ideal only duplicates the wheel.

Sincerely,

Willlam L. Hartzell
Garland, Texas 75044

Post Script:

I received the November 1994 issue just as I was about to mail this. Therein, I found that the C committee is going to do about what I am asking. However, I decided to send this on as my reinforcement to their efforts. Tallyho! Please forward.

We won't have to worry about a shortage of opinions on how to revise Standard C. — pjp

Dear Mr. Plauger:

I've enjoyed this magazine (CUJ — how do we acronym it now? CUJ++, perhaps?), and your writing in general, for many years. Thanks for much useful information on many aspects of computer science, especially my favorite subjects, C and C++. BTW, I also like your science fiction!

I recently wrote an improved (IMHO) replacement for the Windows API function TabbedTextOut, which required me to tokenize the output string so that each token could be drawn at the appropriate tab stop. Naturally, I turned to the C run-time function strtok to perform the tokenization, and discovered something which I found surprising:

The function (I tried a few different versions) won't return a zero-length string when it finds two delimiters together. Example:

"token 1\ttoken 2\t\ttoken 4"
I anticipated (and required) that strtok would return these four strings:

"token 1"
"token 2"
""
"token 4"
However, (no surprise to you, I'm sure, since the version you published does this also), it only returned the three strings of non-zero length. Since the strings my program displays are user-defined and based on data coming from a database populated by a variety of programs, the possibility exists (actually, the certainty exists) that any (or several) field(s) could be zero-length.

So, I had to write my own version which returned the four strings I needed. (No big deal, but I wish I'd found your book earlier, as it appears that simply commenting out a single line of your version of strtok would provide the behavior I expected).

Also, I haven't found any description of strtok which describes the behavior at this level of granularity. My questions:

1. Do all strtoks behave this way, and have they always? I seem to remember doing just the opposite years ago; writing a strtok which did skip the zero-length strings because the library version didn't. If this memory is accurate, it was probably the Aztec compiler for the 6502, my first C compiler (sigh).

2. In discussion with a colleague, we wondered if this behavior was provided (or altered) to help handle free-form language parsing?

3. Why doesn't strtok provide this seemingly useful behavior as an alternative? Or another run-time function which provides the zero-length strings?

Or, am I just confused? :-)

Later,

Kit Kauffmann
kitk@mudshark.sunquest.com
73363,447 (Compuserve)

We didn't explicitly change the behavior of strtok when we standardized it. On the other hand, there may have been some variation among implementations in the field. One of the desirable effects of standardization is to call attention to such variations and encourage vendors to eliminate them. (And, by the way, we've decided to keep the acronym for the magazine as CUJ.) — pjp

PJP,

I have a letter here that is of a different concern. I need your help and the readers help. I am a young programmer, just started programming in C, and am interested in creating arcade style games. However the examples that came with my Borland Turbo C compiler (BGIDEMO.C) are very low-level graphics. (I find I can do the same in Quick Basic.) I really have a strong desire to learn high-level graphics (CD-ROM quality) programming, yet I cannot find any books on the subject. If there are any high-level graphics programmers out there please send me some kind of info on the subject. I would really appreciate some source code in C so I can learn (on disk or documented) how to do this. Whoever gives me the key will have my eternal programming gratitude.

Thanks,

Dan Strohschein
5822 Cassandra Dr.
San Bernardino, CA 92407

P.S. I mean high-level graphics and palette like the cover of C Users Journal, May 1994.

This is not my fort. Anybody out there in the market for some eternal gratitude? — pjp