[comp.object] C++ vs. C

hargrove@asc.slb.com (Jim Hargrove) (04/24/91)

This note is prompted by several postings by Scott Guthery, beginning
with The Emperor Strikes Lethe. I am struck by how different SBG's
experience with object oriented programming differs from my own. I
began programming in C++ about 18 months ago. Prior to that, I worked
mainly in C, though I have used many different languages over the
years. 

I believe that I am writing better programs today after switching to
C++. Here is an example:  Several years ago, I was faced with the
problem of writing display routines for a number of different types
of "objects." Each of these objects could be a block of text, an
appointment page, a calendar, or a "folder" containing other objects.
I wrote the routine as follows:  

void    DisplayObject(Object    * Obj,
                      Window    *   W)
{
    switch(ClassOf(Obj))
    {
        case    Text:
            DisplayText(Obj,W);
            break;
        case    ApptPage:
            DisplayAppt(Obj,W);
            break;
        case    Calendar:
            DisplayCalendar(Obj,W);
            break;
        case    Folder:
            DisplayFolder(Obj,W);
            break
        default:
            Error("Invalid Object");
    }
}

That is a nice, simple routine. Of course we can improve it quite
easily, but there is little incentive to do so. This works; it's easy
to understand; and so long as we don't invent a large number of 
objects, it is relatively easy to maintain.  Today, I would write the
same routine in C++ as 

Obj->Display(W);

which is better both technically and aesthetically. I could have
written the routine the same way five years ago. I could have created
a table of routines containing the address of the function to call to
display each kind of object. The ClassOf function provides a
convenient index into the table. The routine would be simply:

(*DisplayFn[ClassOf(Obj)])(Obj,W);

In ANSI C, I could even dispense with the (*) notation. So, I have to
agree with Scott. There is really nothing new here. The syntax is a
bit different, granted, but we probably don't really have a "paradigm
shift." 

Or do we? The language we speak/write/code in influences the
way we think. In C, I was used to thinking of switch statements.
Indeed, this style of programming is taught extensively. Look at any
book on Window programming, for example. But the use of a virtual
function is much better. It is easier to maintain, since I never have
to modify a DisplayObject routine at all. Moreover, it is more
efficient. 

Notice that the code represented by the original DisplayObject
routine has virtually disappeared! All of the code necessary to
invoke the proper routine is generated by the compiler.  In C++, the
use of a virtual function in this case is obvious. 

If I were to code the routine using a switch statement [and dynamic
type checking :-)] it would look very strange. So, the mere use of an
object oriented langauge has led me to a better overall program. The
fact that the technique used, a jump vector, has been around since
the days of the earliest computers is largely irrelevant. C++ appears
to be a significantly better tool than C.

+--------------------------------------------------------------------+
|These opinions are my own, of course. But you know that.            |
+--------------------------------------------------------------------+
|Internet: hargrove@asc.slb.com                                      |
|Compuserve: ID 74000,1010                                           |
|Mail: Schlumberger Austin Systems Center                            |
|     P.O. Box 200015                                                |
|     Austin, TX 78720-0015                                          |
+--------------------------------------------------------------------+
|Every great scientific truth goes through three stages:             |
|   First, people say it conflicts with the Bible.                   |
|   Next they say it had been discovered before.                     |
|   Lastly, they say they always believed it.                        |
|--Jean Louis Agassiz (1807-1883)                                    |
+--------------------------------------------------------------------+



        -- jwh
-- 

        -- jwh

kornfein@azores.crd.ge.com (Mark M. Kornfein) (04/25/91)

In article <1991Apr24.125926.5146@asc.slb.com> hargrove@asc.slb.com (Jim Hargrove) writes:
>
>This note is prompted by several postings by Scott Guthery, beginning
>with The Emperor Strikes Lethe. I am struck by how different SBG's
>experience with object oriented programming differs from my own. I
>began programming in C++ about 18 months ago. Prior to that, I worked
>mainly in C, though I have used many different languages over the
>years. 
>
>I believe that I am writing better programs today after switching to
>C++. Here is an example:  

[deleted C program and text]


>Obj->Display(W);
>
>which is better both technically and aesthetically. 

This example shows both the power of object oriented programming and a 
drawback of it. The C example is somewhat easier to debug and test than 
the C++ example from my experience. This is especially true if I did not
write the code originally.

From looking at the C++ I have no clear idea what method will be called without
looking further into the Display method and seeing which display method is
envoked for which object.  If I needed to change the Display methods I do not
even know which one's exist from this code.  It is true that a good browser
can help with this problem but in the real world one does not always have that
or even always have access to the executable code.

In the C example this flow of control is perfectly clear, I know all objects 
that can be handled and which piece of code displays which object.


                                       

===============================================================================
Mark Kornfein                            INET: kornfein@crd.ge.com 
GE Corporate R&D Center	                 UUCP: uunet!crd.ge.com!kornfein
Schenectady, NY                          

hargrove@asc.slb.com (Jim Hargrove) (04/26/91)

>>>>> kornfein@azores.crd.ge.com (Mark M. Kornfein) writes:


>> In article <1991Apr24.125926.5146@asc.slb.com> hargrove@asc.slb.com (Jim Hargrove) writes:
>
>This note is prompted by several postings by Scott Guthery, beginning
>with The Emperor Strikes Lethe. I am struck by how different SBG's
>experience with object oriented programming differs from my own. I
>began programming in C++ about 18 months ago. Prior to that, I worked
>mainly in C, though I have used many different languages over the
>years. 
>
>I believe that I am writing better programs today after switching to
>C++. Here is an example:  

>> [deleted C program and text]


>Obj->Display(W);
>
>which is better both technically and aesthetically. 

>> This example shows both the power of object oriented programming and a 
>> drawback of it. The C example is somewhat easier to debug and test than 
>> the C++ example from my experience. This is especially true if I did not
>> write the code originally.

This is a telling argument. In fact, it is the single biggest argument
against the use of C++. All I can say is that my experience in using
C++ indicates that it is easier to maintain than C.

>> From looking at the C++ I have no clear idea what method will be called without
>> looking further into the Display method and seeing which display method is
>> envoked for which object.  If I needed to change the Display methods I do not
>> even know which one's exist from this code.  It is true that a good browser
>> can help with this problem but in the real world one does not always have that
>> or even always have access to the executable code.

Yes, good tools would be a big help. The state of C++ tools today,
especially in the Unix world, is pretty poor. Some stylistic
conventions help. For example, we don't use much overloading of
functions by the type of arguments. This makes it easier to find the
routine to be invoked. And yes, we have occasional surprises, such as
when you single step the Obj->Display(W) routine and wind up somewhere
you don't expect.

BUT, I think you are overlooking a major maintenance flaw of the C
code. When I add a new class of object, I have to modify the
DisplayObject routine coded in C. Even if I use a table of functions,
I still have to modify the table. In C++, the compiler takes care of
both of these tasks. 

AND, I think the technical superiority of the C++ implementation is
significant. It isn't so important when there are only 4 cases. But
what if there are 20 or so? Then the savings in memory and execution
may be really important.
-- 

        -- jwh

njacobs@nssdca.gsfc.nasa.gov (Nick Jacobs) (04/26/91)

In article <1991Apr25.213211.24114@asc.slb.com>, hargrove@asc.slb.com (Jim Hargrove) writes...
 [long discussion of a specific example omitted. See original 
posting.]

>AND, I think the technical superiority of the C++ implementation is
>significant. It isn't so important when there are only 4 cases. But
>what if there are 20 or so? Then the savings in memory and execution
>may be really important.

In this example (and most other cases) there is really no savings in
either memory or execution time. The visible switch is replaced by
invisible (compiler-generated) selection code which decides which
class the object belongs to. The code in the case statements is in
the methods for the individual classes.

IMHO the important issue is ease of maintenance of the code. It's
interesting to see that there are arguments for C, as well as for
C++, on this issue.

> 
>        -- jwh

Nick Jacobs

jls@rutabaga.Rational.COM (Jim Showalter) (04/27/91)

]AND, I think the technical superiority of the C++ implementation is
]significant. It isn't so important when there are only 4 cases. But
]what if there are 20 or so? Then the savings in memory and execution
]may be really important.

Basically, the dynamic dispatching in C++ takes the same space and
time as a non-inheritance version in C, and without decent tools the
debugging is harder than in the C version. On the other hand, you
get simpler looking code in C++, and you eliminate the dual-point-of-
maintenance of the C version. Which is better for you is a very
personal choice.
--
* "Beyond 100,000 lines of code, you should probably be coding in Ada." *
*      - P.G. Plauger, Convener and Secretary of the ANSI C Committee   *
*                                                                       *
*                The opinions expressed herein are my own.              *

dag@control.lth.se (Dag Bruck) (04/27/91)

In article <5111@dftsrv.gsfc.nasa.gov> njacobs@nssdcs.gsfc.nasa.gov writes:
>In article <1991Apr25.213211.24114@asc.slb.com>, hargrove@asc.slb.com (Jim Hargrove) writes...
> [long discussion of a specific example omitted. See original 
>posting.]
>
>>AND, I think the technical superiority of the C++ implementation is
>>significant. It isn't so important when there are only 4 cases. But
>>what if there are 20 or so? Then the savings in memory and execution
>>may be really important.
>
>In this example (and most other cases) there is really no savings in
>either memory or execution time. The visible switch is replaced by
>invisible (compiler-generated) selection code which decides which
>class the object belongs to. The code in the case statements is in
>the methods for the individual classes.

The virtual call of C++ is faster and requires less memory.

	1.  Only one "jumptable" is generated for each class,
	but you need one jumptable for every switch statement
	(typically).  On the other hand, every object with
	virtual functions needs an extra word.

	2.  The virtual call is simpler than a switch and therefore
	faster.   Empirical data was presented at one of the USENIX
	C++ conferences (1988 or 1989).

>IMHO the important issue is ease of maintenance of the code.

I completely agree.

	-- Dag

dlw@odi.com (Dan Weinreb) (04/28/91)

In article <18905@crdgw1.crd.ge.com> kornfein@azores.crd.ge.com (Mark M. Kornfein) writes:

   This example shows both the power of object oriented programming and a 
   drawback of it. The C example is somewhat easier to debug and test than 
   the C++ example from my experience. This is especially true if I did not
   write the code originally.

   From looking at the C++ I have no clear idea what method will be called without
   looking further

I could use the same argument to explain why subroutines are not a
good idea in programming languages.  You should never use subroutines,
procedures, or functions.  You should always just write out all of the
code, in line.  After all, if I'm reading a program and find a call to
a subroutine called "foo", I have no idea what it does.  I'd have to
search all over to try to find "foo", and heaven knows where it might
be.  Subroutines just make programs incomprehensible.  As you say
yourself, "It is true that a good browser can help with this problem
but in the real world one does not always have that".

When I first started to use computers, there were always CREF
(cross-reference) programs, that would print out lists of where each
subroutine was defined and where it was referenced.  They also existed
for assemblers, this time applying to defined symbols rather then
subroutines, of course.  I found these cross-references utterly
indispensible when I wanted to read real (large) programs.  Nowadays
the job gets done on-line by my programming environment (e.g. "tags"
and the Gnu Emacs meta-. command).  The introduction of subroutines
effectively mandated these improvements in programming technology, and
they always existed in any real programming situation I found myself
in.

Object-oriented programming, with its new kind of subroutines
(generic, or virtual, or message passing, or whatever), similarly
demand cross-referencing tools.  The best ones I've ever seen are in
the Symbolics Genera environment, for Flavors/CLOS.  I program in C++
these days, and do not have tools as good as that, and wish I did.  In
general, I think the C++ world has not yet caught up with the need for
good program development environment tools, particularly in the area
of cross-referencers.  There are a lot of good starts that might turn
into something great one day, but it's not really here yet.  This is
one of the ways in which C++ is really still in its early days.

Indeed, some people might not want to get involved with C++ yet; they
might want to wait until the environments are better developed, until
parameterized types are available in all the leading compilers, until
more off-the-shelf libraries exist, and so on.  That's proper for some
people and companies and groups.  Those of us who are using C++ now
are to some degree pioneers, and we have to pay something in exchange
for using C++ earlier in its history.

And for people who want to use an OO language now and are picking
among the alternatives, one of the many considerations to take into
account is that some environments have better-developed tools than
others.  I know that the Symbolics Flavors/CLOS one is very well
developed.  I understand that the ParcPlace-based Smalltalk-80 one is,
too.  Probably many others are; I'm not familiar with most.

The point is that when you evaluate the "power of object oriented
programming", you really can't omit consideration of the programming
environment.

hargrove@asc.slb.com (Jim Hargrove) (04/29/91)

>>>>> jls@rutabaga.Rational.COM (Jim Showalter) writes:


>> ]AND, I think the technical superiority of the C++ implementation is
>> ]significant. It isn't so important when there are only 4 cases. But
>> ]what if there are 20 or so? Then the savings in memory and execution
>> ]may be really important.

>> Basically, the dynamic dispatching in C++ takes the same space and
>> time as a non-inheritance version in C, and without decent tools the
>> debugging is harder than in the C version. On the other hand, you
>> get simpler looking code in C++, and you eliminate the dual-point-of-
>> maintenance of the C version. Which is better for you is a very
>> personal choice.
>> --

Well, two posters have made this point, so I have to reply. The fact
is that most compilers will generate better code for the virtual
function dispatching than for the switch statement *in the specific
case cited.*

The reason is that the switch involved a number of *similar* function
calls. Most compilers will not detect that the arguments being passed
to the function are the same for all calls. As a consequence, the code
to construct the calling sequence -- pushing parameters on the stack
or whatever-- will be repeated for each case. 

I once converted a similar switch statement that contained 22 switches
to use a table of procedures. The code size was reduced by about 4K.
Maybe that wasn't a very smart compiler, or maybe it was a
particularly poor architecture, but the point remains valid. I think
that most compilers will generate better code using a virtual function
table. 
-- 

        -- jwh