FAQs in section [27]:
[27.1] What's the difference between C++ and Smalltalk?
Both fully support the OO paradigm. Neither is categorically and universally
"better" than the other. But there are
differences. The most important differences are:
Note: Many new C++ programmers come from a Smalltalk background. If
that's you, this section will tell you the most important things you need know
to make your transition. Please don't get the notion that either language is
somehow "inferior" or "bad", or that this section
is promoting one language over the other (I am not a language bigot; I serve on
both the ANSI C++ and ANSI Smalltalk standardization
committees). Instead, this section is designed to help
you understand (and embrace!) the differences.
[ Top | Bottom | Previous section | Next section ]
[27.2] What is "static typing," and how is it
similar/dissimilar to Smalltalk?
Static typing says the compiler checks the type safety of every operation
statically (at compile-time), rather than to generate code which will
check things at run-time. For example, with static typing, the signature
matching for function arguments is checked at compile time, not at run-time.
An improper match is flagged as an error by the compiler, not by the run-time
system.
In OO code, the most common "typing mismatch" is invoking a member function
against an object which isn't prepared to handle the operation. E.g., if
class Fred has member function f() but not g(), and fred is an
instance of class Fred, then fred.f() is legal and fred.g()
is illegal. C++ (statically typed) catches the error at compile time, and
Smalltalk (dynamically typed) catches the error at run-time. (Technically
speaking, C++ is like Pascal pseudo statically typed since pointer
casts and unions can be used to violate the typing system; which reminds me:
only use pointer casts and unions as often as you use gotos).
[ Top | Bottom | Previous section | Next section ]
[27.3] Which is a better fit for C++: "static typing" or
"dynamic typing"? 
[Recently added cross references to evilness of macros (on 3/00). Click here to go to the next FAQ in the "chain" of recent changes.]
[For context, please read
the previous FAQ].
If you want to use C++ most effectively, use it as a statically typed language.
C++ is flexible enough that you can (via pointer casts, unions, and #define
macros) make it "look" like Smalltalk. But don't. Which reminds me: try to
avoid #define: it is evil in 4 different ways: evil#1,
evil#2, evil#3, and
evil#4.
There are places where pointer casts and unions are necessary and even
wholesome, but they should be used carefully and sparingly. A pointer cast
tells the compiler to believe you. An incorrect pointer cast might corrupt
your heap, scribble into memory owned by other objects, call nonexistent member
functions, and cause general failures. It's not a pretty sight. If you avoid
these and related constructs, you can make your C++ code both safer and faster,
since anything that can be checked at compile time is something that doesn't
have to be done at run-time.
If you're interested in using a pointer cast, use the new style pointer casts.
The most common example of these is to change old-style pointer casts such as
(X*)p into new-style dynamic casts such as dynamic_cast<X*>(p),
where p is a pointer and X is a type. In addition to dynamic_cast,
there is static_cast and const_cast, but dynamic_cast is the one that
simulates most of the advantages of dynamic typing (the other is the typeid()
construct; for example, typeid(*p).name() will return the name of the
type of *p).
[ Top | Bottom | Previous section | Next section ]
[27.4] How do you use inheritance in C++, and is that
different from Smalltalk? 
[Recently renamed "subclass" to "derived class" (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]
Some people believe that the purpose of inheritance is code reuse. In C++,
this is wrong. Stated plainly, "inheritance is not for code reuse."
The purpose of inheritance in C++ is to express interface compliance
(subtyping), not to get code reuse. In C++, code reuse usually comes via
composition rather than via inheritance. In other words, inheritance is mainly
a specification technique rather than an implementation technique.
This is a major difference with Smalltalk, where there is only one form of
inheritance (C++ provides private inheritance to mean "share the code but
don't conform to the interface", and public inheritance to mean "kind-of").
The Smalltalk language proper (as opposed to coding practice) allows you to
have the effect of "hiding" an inherited method by providing an
override that calls the "does not understand" method. Furthermore Smalltalk
allows a conceptual "is-a" relationship to exist apart from the
inheritance hierarchy (subtypes don't have to be derived classes; e.g., you can make
something that is-a Stack yet doesn't inherit from class Stack).
In contrast, C++ is more restrictive about inheritance: there's no way to make
a "conceptual is-a" relationship without using inheritance (the C++ work-around
is to separate interface from implementation via ABCs).
The C++ compiler exploits the added semantic information associated with public
inheritance to provide static typing.
[ Top | Bottom | Previous section | Next section ]
[27.5] What are the practical consequences of
differences in Smalltalk/C++ inheritance? 
[Recently renamed "subclass" to "derived class" (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]
[For context, please read the previous FAQ].
Smalltalk lets you make a subtype that isn't a derived class, and allows you to make
a derived class that isn't a subtype. This allows Smalltalk programmers to be very
carefree in putting data (bits, representation, data structure) into a class
(e.g., you might put a linked list into class Stack). After all, if
someone wants an array-based-Stack, they don't have to inherit from Stack;
they could inherit such a class from Array if desired, even though an
ArrayBasedStack is not a kind-of Array!
In C++, you can't be nearly as carefree. Only mechanism (member function
code), but not representation (data bits) can be overridden in derived classes.
Therefore you're usually better off not putting the data structure in a
class. This leads to a stronger reliance on abstract base
classes.
I like to think of the difference between an ATV and a Maseratti. An ATV (all
terrain vehicle) is more fun, since you can "play around" by driving through
fields, streams, sidewalks, and the like. A Maseratti, on the other hand, gets
you there faster, but it forces you to stay on the road. My advice to C++
programmers is simple: stay on the road. Even if you're one of those people
who like the "expressive freedom" to drive through the bushes, don't do it in
C++; it's not a good fit.
[ Top | Bottom | Previous section | Next section ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Jul 10, 2000
|