I spent a week last fall at Software
Development '95 East in my hometown of Washington, DC. The show was a big
improvement over the previous year--more attendees, more exhibitors, more
parties. It's taken this long for the east-coast show to catch on. It was in
Boston for a while and then in DC starting last year. I'm glad that DC worked
out, because I like having an excuse to return home every year.
It's fun to take Judy to these shows. As one of the speakers, I can usually
wangle a pass for her. They make a copy of my badge and substitute her name,
which identifies her as an editor for DDJ. That gets her all kinds of
attention from exhibitors who schmooze for favorable mention in this magazine.
Judy and I go our separate ways among the exhibitors. I pick my route based on
what's new for C/C++ developers: This booth is showing an interesting
programmer's editor, another has a new compiler version, and still others have
class libraries, debuggers, and so on. Judy plans her tour based on who's got the
freebies: A yo-yo over here, fly swatters over there, T-shirts, buttons,
ball-point pens, tote bags, an indoor boomerang. It's lucky we drove up from
Florida in the minivan.
On Thursday evening, we went to the Symantec product-announcement party. The
announcement presentation was a real yawner. The presenter got cute and tried an
unrehearsed demonstration involving a lot of ad hoc code on the overhead screen.
Members of the audience were calling out code corrections while the presenter
fumbled and hemmed and hawed his way through the exercise, which never worked.
Some of us slept through it. Everyone stayed, though, because the free beer and
food wasn't available until the presentation was complete. They sure know how to
hold onto an audience of programmers.
At the party, Symantec gave away C++ compiler CD-ROMs, which did not interest
Judy. When they ran out of CD-ROMs, they gave away T-shirts and a promise to mail
a CD-ROM. Judy went for the T-shirt. They wouldn't give her one. Turns out you
needed a coupon to qualify, and she didn't have one. She puffed out her
DDJ editor's badge and tried to look important but to no avail. The
T-shirt official was immutable. She returned to the table empty-handed and vowed
never again to wear last year's Symantec T-shirt, which she treasures because it
was given to her personally by none other than Gene Wang. She said that if Gene
had been there this year, she would have gotten one of those new T-shirts. It's
not fun being around Judy when she's been snubbed this way. Fortunately, they
soon ran out of beer and food, too. "It figures," she said, and we left
along with everyone else. They were boxing up the remaining T-shirts as we walked
out. Judy looked the other way. "I should've worn my new Borland
T-shirt," she whispered.
I spoke to one of the Borland C++ compiler developers about impending Version
5.0. It was a bit confusing, not because of the compiler, but because the
developer was the one I used to talk to at Symantec. He switched to Borland at
about the same time that Borland's chief compiler guy went to Microsoft. Gene
Wang used to work for Borland and jumped to Symantec a couple of years ago amidst
a flurry of ado about trade secrets and such. Before that, Borland's Brad
Silverberg moved to Microsoft. As a result of all these shifts, we had to cancel
our annual Benedict Arnold Loyalty award; the playing field got to be too
even.
Anyway, back to Borland C++ 5.0. The Borland developer told me that the new
compiler would have all the new ANSI features described in the April '95 draft
specification, which would once again put Borland C++ ahead of Microsoft Visual
C++ 4.0, which is missing most of the new stuff. I asked about support for
Microsoft Foundation Classes in the Borland compiler. He said that the compiler
would support but not distribute MFC, which means that if you can get hold of the
MFC source code (distributed with Visual C++), Borland C++ will compile it. I
expect that Borland's visual-development environment will work with MFC, too, but
don't quote me. I asked why Borland would not distribute MFC as Watcom and
Symantec do. The developer said that Microsoft refuses to license the MFC
technology to Borland. The two companies have been arch rivals for years. Gates
has been quoted as saying that he hates Philippe Kahn. Hates? If I had umpty-ump
billion dollars, I'd love everybody--even Philippe. Wake up, Bill. Philippe went
to another company. Borland has a significant slice of the compiler market. It
would be nothing but good for Microsoft if all those programmers were using
MFC.
My favorite SD '95 East exhibit was not software at all, but a hardware device,
one of those obvious things that, as soon as you see it, you wonder why you
didn't think of it. SoftBoard from Microfield Graphics is a whiteboard interfaced
to a PC. At first you don't believe it. A conventional-looking whiteboard sits on
an easel next to the PC. Selecting a color dry-erase marker from the tray, you
draw a picture or write something on the whiteboard. As you do, a Windows
application in the PC, which has a white window the same shape as the whiteboard,
displays what you mark. You can save the picture as a bitmap file.
How did they do it? First, the whiteboard is not conventional at all. It casts
laser scanners in two axes across the face of the whiteboard. Second, the markers
are not conventional either. Each marker has a band with a bar code just above
the tip. The scanners read the bar code and send the coordinates and code to the
PC through the serial port. The code identifies the color, and the application
does the rest.
This is not only cool, it has lots of potential. In my C and C++ training
classes, I often use the whiteboard to amplify a concept or answer a question.
The students hastily copy the charts into their notes because I'll be erasing the
picture to make room for the next explanation. How convenient, timesaving, and
accurate it would be if students could push a button and save those illustrations
electronically with all the information intact. This technology also solves one
of my objections about remote training across a network, where the students have
an audio/video window of the instructor but no way to clearly see or capture the
whiteboard presentations. SoftBoard is not cheap. The smallest one is about
$2800, but it solves several long-standing problems associated with training and
presentations. If they had been handing out samples at the show, I'd have sent
Judy to their booth right off.
The highlight of the show was the keynote address by Jim McCarthy, Microsoft's
product manager for Visual C++. He addressed the problems of schedules, slippage,
and shipping versions in large software projects. His observations hit the mark
every time. One of them (my favorite) describes his answer to managers who find
it unacceptable if a programmer does not know when something is going to be
finished. Jim says that it is just too bad. They can't hire someone who knows;
they can only hire someone who lies. He told the story of a Visual C++ feature,
originally estimated to take four months, then estimated to take ten, causing it
to miss the ship date for the next release. Jim wanted that feature and sent his
programmers away to think about it. Two days later they came back. How long did
they think it would take after giving it more thought? Forget it, they said, it's
completed. In the course of reconsidering their estimate, they had just gone
ahead and implemented the feature. His point? Those are the best programmers in
the business, and they don't know the difference between a ten-month feature and
a two-day feature. The practice of estimating software development is a long way
from being understood, much less accurate.
The ANSI X3J16 committee published a draft specification in April 1995 for public
review. Presumably, it was meant for public comment, too, but they failed to
allow sufficient time for anyone to analyze the new language in any detail.
Furthermore, if my experience is typical, comments from the public are
stonewalled as soon as they are submitted. The committee wants to get on with its
work and apparently does not want to be bothered by public reaction. I heard that
the committee's position is that the public had sufficient time to react prior to
the publication of this document. True enough if you are on the committee and
privy to their deliberations. Those of us who are not had little opportunity
between the document's availability and the cutoff date for comments for a
comprehensive review.
It could be argued that anyone that interested should be on the committee, a
participant rather than a critic. It can be counterargued that commentators,
particularly in the press, must preserve the objectivity of the outsider looking
in. An activist forms emotional commitments to issues based on not-always-equal
quantities of ego and merit. Besides, I hate meetings.
The committee has made substantial changes in the area of templates and the
standard library. We are correct to raise concerns about how well those changes
have been tested and validated in so little time with no mature compilers
available to implement them. The public deserves a better shot at a specification
that is bound to change the way we work for the next several years.
There are many small changes to the language that have minor consequences. The
mutable and typename keywords. The bool type. You can use
them or ignore them. There are many substantial changes, too, such as the
namespace feature and the specification of a standard exception hierarchy. These
should not be ignored because they solve serious deficiencies in traditional C
and C++.
But the committee wears two masks. If you suggest a change that they prefer not
to consider, they fall back on the time-worn argument that the change breaks too
much existing code, whether or not it does. But when they want to make a change,
regardless of its consequences to existing code, they just up and make it. Well,
maybe not in such a cavalier fashion, but they do it nonetheless. This tendency
is not rampant, but it occurs enough to make me uncomfortable.
Case in point. I suggested that the ifstream::read and
ofstream::write functions be changed from using char* and
int parameters to using void* and size_t parameters.
This would eliminate casts when the buffer argument was not a char array
or pointer and would permit a program to read and write buffers greater in length
than the limits of a signed integer (32K on a 16-bit int implementation).
I discussed this situation with Bjarne Stroustrup, who agreed that the
specification should change. He called it a bug. (Actually, we discussed only the
int versus size_t part of the issue.) I submitted the
recommendation to the committee. The answer came back that this change would
break too much existing code. Not understanding how, I asked for an example. I'm
still waiting for an answer. I suppose that an implementation that uses an
int wider than its size_t could have problems, but do such
implementations exist? I don't know. If I can allocate a record buffer with a
size_t size argument, why can't I read a record into that block with the
same argument?
A look at the specification reveals why the committee might not want to consider
such a change. The code that would be broken is in the document itself, not in
programs out in the real world. Because virtually everything in the standard
library is now specified as a template implementation, the types for those
parameters are not what they used to be in traditional C++. They are now
specified with typedefs rather than intrinsic types. The buffer
argument is a pointer to char_type, which is almost impossible to
interpret because they left it out of the document's index. I found its
typedef in a header file in the document. It's a charT, which is
also missing from the index, but which turns out to be a template argument, so it
could wind up being anything. The read and write functions' size arguments are of
type streamsize. The streamsize type is typedefed as
an INT_T, which is either int or wint_t depending on what CHAR_T
is. If anybody suggested to me that I change something inside that mess as a
volunteer and for no pay, I'd tell them whatever it took to make them go away.
Here's a change the committee made. The new specification for declarations in the
first expression of a for statement reveals an insidious problem. Example 1(a) is taken from the specification.
The specification states that "...the scope of the name(s) declared extends
to the end of the for-statement." This is quite different from
how the C++ language works now.
A lot of existing code will be broken by this change. In fact, the committee's
example does not even compile with contemporary compilers because the
declaration, under current rules, is in the same scope as the for
statement. Example 1(b) shows the effective
code and scope if you substitute an independent declaration and a while
loop.
Clearly, you could not declare another i integer after the while
loop because the first i integer is still in scope. And here's where
the ANSI specification springs a leak. Earlier on the same page, the
specification uses just such an example to demonstrate the operation of the
for statement. C'mon guys, which way is it?
Example 1(c) shows a common idiom that uses the
current rules to advantage. Change the rule, and a lot of similar code no longer
compiles. If there happens to be another int i in an outer scope in Example 1(c), the program compiles okay under
the new rule, but it stops working properly.
Bjarne Stroustrup prefers the new rule and wishes he had specified it that way
originally. If he had, this issue would not exist today. He did not, however, and
now he has successfully campaigned to have the committee correct what he
perceives to be his earlier mistake. Over the years Bjarne's influence has led
the committee down many paths, mostly good. His championing of STL and the
template changes that STL needs, for example, was a major step forward for the
language. But this change is, in my opinion, a mistake. That's because: 1. I
really like the earlier usage; and 2. I don't think the change's benefits
outweigh its consequences.
Bjarne disagrees. The decision to effect this change was not made lightly.
According to him, the decision was debated and postponed for years because of
concerns for existing code, teaching materials, compilers, and so on. His winning
argument to the committee in favor of the change was:
You will have programmers complaining whatever you decide, but personally I
will feel better defending the cleaner and--based on experience--more intuitive
rule than apologizing for the old rule and explaining what code the change would
break.
So it is what it is, and for a time we will be in transition until all compilers
comply and all old programs are converted. During the interim I would encourage
compiler vendors to include a compile-time option, perhaps a pragma, that
retreats to the older rule. Better yet, a warning that alerts programmers about
the potential change to what was an overriding scope. Programmers should code to
the new rule, but if an older program fails to work properly with a new compiler,
this new behavior might be the problem.
I don't know if this next change is intentional or merely the result of one
compiler vendor's interpretation of an ambiguous specification. It turned up when
I ported the code in Example 2(a) from Visual
C++ 2.0 to the beta Visual C++ 4.0. Example
2(b) is the message the compiler returned to me.
According to Microsoft's interpretation of the ANSI specification, you have to
overload the arithmetic operators for enum types. The relational operators
still work the way they always did. Example
2(c) shows the overloaded operator function for the postfix ++
operator. After that, you need the prefix ++ operator, the two decrement
operators, the binary addition and subtraction operators, and the op-equal
addition and subtraction operators. Finally, all those operators must be
overloaded for any other enum types you define.
I pored through the ANSI draft specification, but I could not determine from the
document with any degree of certainty whether Microsoft's so-called new behavior
is proper or improper. Unless I missed something, which is possible given the
complexity of the document, this behavior is totally implementation dependent,
subject to the compiler builder's interpretation of the specification. If that
assumption is correct, the portability of the language has been seriously
compromised. If incorrect, and Microsoft is right, this change to the way that
enum variables work might make for a more type-safe language, but it will
certainly break a lot of existing code. If Microsoft is wrong, the committee
needs to tighten up the specification.
In a recent column, I expressed my opinion that the Microsoft Foundation Class
(MFC) library is the best of the Windows program-framework class libraries. That
opinion generated more heated response than anything I've said since I suggested
that OS/2's installation procedure makes huge vacuum-cleaner noises. I seem to
know the way to the heart of a programming religious issue. Mostly I heard from
programmers who prefer Borland's Object Windows Library (OWL) over MFC. OWL is,
they say, more object oriented than MFC. Maybe. Is that necessarily true and, if
so, is it better? It's a matter of opinion. Does OWL encapsulate more of the
Windows API than MFC? Perhaps. It seems to. OWL also seems to hide more of the
API, making it more difficult to get at things either not supported or
encapsulated in a way that the programmer wishes to override. These discussions,
mostly online, went on for a time, devoting only the first few messages to the
relative merits of either class library. After that, they concentrated on what
constitutes a de facto standard, whether Microsoft is force-feeding us something,
and whether the trade press (me) is being taken in by hype. More message
bandwidth was given to Microsoft bashing and defending than to the technical
issues, which might point to the true heart of the religious wars.
The two sides squared off and fired their volleys back and forth. It was a
friendly exchange, and I won't go further into the details of the battle. Mostly
I stood back to see which way it went.
It soon became evident that if you start with MFC, you like MFC; if you start
with OWL, you like OWL. Most of the commentators had not spent a lot of time with
both products, which is to be expected. You do not, in the course of making a
living, dedicate substantial time to two competing, mutually exclusive tools. It
is natural, then, to prefer the one you use. The respondents seemed to believe
that C programmers who already knew the Windows C API preferred MFC, while C++
programmers with little or no exposure to Windows programming preferred OWL. That
was not my experience. I am in the latter group and prefer MFC. But, having
developed DOS application-framework function and class libraries (D-Flat and
D-Flat++), my experience and bias might not be typical.
A recurring theme was that influential columnists are irresponsible when they
state their opinions so unequivocally. That position is taken only by those who
disagree with the opinions, of course. First, you overestimate my influence. I
could write until my mug was cerulean about my favorite programmer's editor, and
not one of you would switch. Second, what difference does it make if a few people
decide to use what I use. If it works for me, it should work for them. Are
programmers somehow diminished when their choice is the different (or same)
drummer? I don't think so.
I expected objections from the vendors of the competing class libraries, but they
didn't make a peep. Maybe they dismiss my opinions as the wild ranting of an
uncontrollable and out-of-control programmer. Maybe they're right. On the other
hand, maybe they secretly agree with me. I doubt it.
Those of you who cared enough to object got one thing right. My experience with
OWL is probably not current enough to simply say that MFC is better. I like MFC
better, so I use it, which accounts for my more current knowledge of its
capabilities. I did not intend to give the impression that other class libraries
are not worth a look.
Borland C++ 5.0
SoftBoard
JMcC's Keynote
ANSI C++ Innovations
ifstream::read and ofstream::write
A New for Statement
enum as a Type
MFC versus OWL
Example 1: (a) New C++ for statement; (b) the
effective code and scope if you substitute an independent declaration and a while
loop; (c) common idiom that uses the current rules to advantage.
(a)
int i = 42;
int a[10];
for (int i = 0; i < 10; i++)
a[i] = 1;
int j = i; // j = 42;
(b)
int i = 0;
while (i < 10) {
a[i] = i;
i++;
}
(c)
for (int i = 0; i < maxentries; i++) {
// ...
if ( ... ) // some loop-terminating condition
break;
}
if (i < maxentries)
// the loop was broken before reaching the end
Example 2: (a) Code being ported from Visual C++ 2.0 to the beta Visual C++ 4.0; (b) message returned from the compiler; (c) the overloaded operator function for the postfix ++ operator.
(a)
enum Color { red, green, blue };
int main()
{
Color clr = red;
clr++;
return 0;
}
(b)
error C2676: binary '++' : 'enum
Color' does not define this
operator or a conversion to a
type acceptable to the predefined
operator (new behavior; please see help)
(c)
Color operator++(Color& c, int)
{
Color temp = c;
int cc = c;
c = static_cast<Color>(++cc);
return temp;
}