topical media & game development

talk show tell print

object-oriented programming

Comparing Smalltalk, Eiffel, C++ and Java

subsections:


The languages Smalltalk, Eiffel, C++ and Java may be regarded as the four most important (and popular) representatives of classical object-oriented languages, classical in the sense of being based on a class/object distinction.

Criteria for comparison


slide: Criteria for comparison

In this section we will compare these languages with respect to what may be called their intrinsic language characteristics. Before that, however, we will indicate some other (more external) criteria for comparison such as the availability of class libraries and the existence of a programming environment. See slide 5-comparison. Our discussion is based on (but in some respects disagrees with and extends)  [BPS89].

Criteria for comparison

When choosing a particular programming language as a vehicle for program development a number of factors play a role, among which are the availability of a class library, the existence of a good programming environment, and, naturally, the characteristics of the language itself.

Class libraries

An important criterion when selecting a language may be the availability of sufficient class library support. A general class library, and preferably libraries suitable for the application domain one is working in, may drastically reduce development time. Another important benefit of using (well-tested) class libraries is an improvement of the reliability of the application.

Smalltalk (that is Smalltalk-80 of ParcPlace Systems) comes with a large collection of general purpose and graphics programming classes, that are identical for both MS-DOS and Unix platforms. Also Eiffel comes with a standard collection of well-documented libraries containing common data structures, container classes and classes for graphics programming. For both Smalltalk and Eiffel, the accompanying classes may almost be considered to be part of the language definition, in the sense that they provide a standard means to solve particular problems.

In contrast, for C++ there is almost no standard library support (except for IO stream classes). Even worse, the various C++ compiler vendors disagree considerably in what functionality the standard class libraries of C++ must offer. Fortunately, however, there is an increasingly large number of third party libraries (commercially and non-commercially) available. The burden of choosing the appropriate libraries is, however, placed on the shoulders of a user or a company, which has the advantage that a more optimal solution may be obtained than possible within the confines of standard libraries.

Java, on the other hand, offers an overwhelming amount of APIs, including a Reflection API, for meta programming, APIs for networking, communication, and APIs for multimedia and 3D. Perhaps the greatest benefit of Java is the effort put into the standardization of these APIs.

Programming environments

Another selection criterion in choosing a language is the existence of a good programming environment. What constitutes a good programming environment is not as simple as it may seem, since that depends to a large extent upon the experience and preferences of the user. For example, with respect to operating systems, many novice users favor a graphical interface as originally offered by the Apple Macintosh computers, while experienced users often feel constrained by the limitations imposed by such systems. In contrast, experienced users may delight in the terseness and flexibility of the command-based Unix operating system, which leads to outright bewilderment with many novice users.

Of the object-oriented programming languages we consider, Smalltalk definitely offers the most comprehensive programming environment (including editors, browsers and debuggers). Eiffel comes with a number of additional tools (such as a graphical browser, and a program documentation tool) to support program development (and maintenance).

In contrast, C++ usually comes with nothing at all. However, increasingly many tools (including browsers and debuggers) have become available.

For Java there are a number of IDEs (Integrated Development Environments) available, most of which run only on the PC platform.

Language characteristics

Despite the commonality between Smalltalk, Eiffel, C++ and Java (which may be characterized by saying that they all support data abstraction, inheritance, polymorphism and dynamic binding), these languages widely disagree on a number of other properties, such as those listed in slide 5-characteristics.

Language characteristics

  • uniformity of data structures
  • documentation value
  • reliability
  • inheritance mechanisms
  • efficiency
  • memory management
  • language complexity

slide: Language characteristics

These characteristics were used in  [BPS89] to compare Smalltalk, Eiffel and C++ with the language Oberon, which offers what may be called a minimal (typed) object-oriented language. We will, however, limit our discussion here to Smalltalk, Eiffel, C++, and, additionally, Java.

Language characteristics

Smalltalk, Eiffel, C++ and Java differ with respect to a number of language characteristics. An indication of the differences between these languages is given slide
5-language-characteristics. This characterization conforms to the one given in  [BPS89], with which I think the majority of the object-oriented community will agree. It is further motivated below. However, the places indicated by an asterisk deserve some discussion. In particular, I wish to stress that I disagree with characterizing the reliability of C++ as low. (See below.)

Uniformity

In Smalltalk, each data type is described by a class. This includes booleans, integers, real numbers and control constructs. In Eiffel there is a distinction between elementary data types (such as boolean, integer and real) and (user-defined) classes. However (in the later versions of Eiffel) the built-in elementary types behave as if declared by pre-declared classes. For C++, the elementary data types and simple data structures (as may be defined in C) do not behave as objects. To a certain extent, however, programmers may deal with this non-uniformity by some work-around, for example by overloading functions and operators or by embedding built-in types in a (wrapper) class. Java may be regarded as a simplified version of C++. Due to its restrictions, such as the absence of operator overloading and type casts, the language appears to be more uniform for the programmers.

Documentation value

Smalltalk promotes a consistent style in writing programs, due to the assumption that everything is an object. One of perhaps the most important features of Eiffel is the use of special keywords for constructs to specify the correctness of programs and the behavioral properties that determine the external interface of objects. Moreover, Eiffel provides a tool to extract a description of the interface of the method classes (including pre- and post-conditions associated with a method) which may be used to document (a library of) classes. To my taste, however, the Eiffel syntax leads to somewhat verbose programs, at least in comparison with programs written in C++.

The issue of producing documentation from C++ is still open. A number of tools exist (including a WEB-like system for C++ and a tool to produce manual pages from C++ header files) but no standard has yet emerged. Moreover, some people truly dislike the terseness of C/C++. Personally, I prefer the C/C++ syntax above the syntactical conventions of both Eiffel and Smalltalk, provided that it is used in a disciplined fashion.

Java programs may be documented using javadoc. The javadoc program may be regarded as the standard C++ has been waiting for, in vain.

Reliability

Smalltalk is a dynamically typed language. In other words, type checking, other than detecting runtime errors, is completely absent. Eiffel is generally regarded as a language possessing all characteristics needed for writing reliable programs, such as static type checking and constructs for stating correctness assertions (which may be checked at runtime). Due to its heritage from C, the language C++ is still considered by many as unreliable. In contrast to C, however, C++ does provide full static type checking, including the signature of functions and external object interfaces as arise in independent compilation of module files. Nevertheless, C++ only weakly supports type checking across module boundaries. Contrary to common belief, Eiffel's type system is demonstrably inconsistent, due to a feature that enables a user to dynamically define the type of a newly created object in a virtual way (see section self-reference). This does not necessarily lead to type-insecure programs though, since the Eiffel compiler employs a special algorithm to detect such cases. The type system of C++, on the other hand, is consistent and conforms to the notion of subtype as introduced informally in the previous part. Nevertheless, C++ allows the programmer to escape the rigor of the type system by employing casts.

An important feature of Eiffel is that it supports assertions that may be validated at runtime. In combinations with exceptions, this provides a powerful feature for the development of reliable programs.

At the price of some additional coding (for example, to save the current state to enable the use of the old value), such assertions may be expressed by using the assert macros provided for C++.

In defense of C++, it is important to acknowledge that C++ offers adequate protection mechanisms to shield classes derived by inheritance from the implementation details of their ancestor classes. Neither Smalltalk nor Eiffel offer such protection.

Java was introduced as a more reliable variant of C++. Java's reliability comes partly from the shielded environment offered by the Java virtual machine, and partly from the absence of pointers and the availability of built-in garbage collection. Practical experience shows that for the average student/programmer Java is indeed substantially less error-prone than C++.

Inheritance

Smalltalk offers only single inheritance. In contrast, both Eiffel and C++ offer multiple inheritance. For statically typed languages, compile-time optimizations may be applied that result in only a low overhead. In principle, multiple inheritance allows one to model particular aspects of the application domain in a flexible and natural way.

As far as the assertion mechanism offered by Eiffel is concerned,  [Meyer88] gives clear guidelines prescribing how to use assertions in derived classes. However, the Eiffel compiler offers no assistance in verifying whether these rules are followed. The same guidelines apply to the use of assertions in C++, naturally lacking compiler support as well.

The Java language offers only single (code) inheritance, but allows for multiple interface inheritance. The realization of (multiple) interfaces seems to be a fairly good substitute for multiple (implementation) inheritance.

Efficiency

Smalltalk, being an interpreted language, is typically slower than conventionally compiled languages. Nevertheless, as discussed in section self-implementation, interpreted object-based languages allow for significant optimizations, for example by employing runtime compilation techniques.

The compilation of Eiffel programs can result in programs having adequate execution speed. However, in Eiffel dynamic binding takes place in principle for all methods. Yet a clever compiler can significantly reduce the number of indirections needed to execute a method.

In contrast to C++, in Eiffel all objects are created on the heap. The garbage collection needed to remove these objects may affect the execution speed of programs.

C++ has been designed with efficiency in mind. For instance, the availability of inline functions, and the possibility to allocate objects on the runtime stack (instead of on the heap), and the possibility to declare friend functions and classes that have direct access to the private instance variables of a class allow the programmer to squeeze out the last drop of efficiency. However, as a drawback, when higher level functionality is needed (as in automatic garbage collection) it must be explicitly programmed, and a similar price as when the functionality would have been provided by the system has to be paid. The only difference is that the programmer has a choice.

At the time of writing there does not exist a truly efficient implementation of the Java language. Significant improvements may be expected from the JIT (Just In Time) compilers that produce native code dynamically, employing techniques as originally developed for the Self language, discussed in section Self.

Language complexity

Smalltalk may be regarded as having a low language complexity. Control is primarily effected by message passing, yet, many of the familiar conditional and iterative control constructs reappear in Smalltalk programs emulated by sending messages. This certainly has some elegance, but does not necessarily lead to easily comprehensible programs.

Eiffel contains few language elements that extend beyond object-oriented programming. In particular, Eiffel does not allow for overloading method names (according to signature) within a class. This may lead to unnecessarily elaborate method names. (The new version of Eiffel (Eiffel-3) does allow for overloading method names.)

Without doubt, C++ is generally regarded as a highly complex language. In particular, the rules governing the overloading of operators and functions are quite complicated. The confusion even extends to the various compiler suppliers, which is one of the reasons why C++ is still barely portable. Somewhat unfortunately, the rules for overloading and type conversion for C++ have to a large extent been determined by the need to remain compatible with C. Even experienced programmers need occasionally to experiment to find out what will happen.

According to  [BPS89], C++ is too large and contains too much of the syntax and semantics inherited from C. However, the validity of their motto small is beautiful is not as obvious as it seems. The motivations underlying the introduction of the various features incorporated in C++ are quite well explained in  [Stroustrup97]. The main problem, to my mind, in using C++ (or any of the object-oriented languages for that matter) lies in the area of design. We still have insufficient experience in using abstract data types to define a complete method and operator interface including its relation to other data types (that is its behavior under the various operators and type conversions that apply to a particular type). The problem is hence not only one of language design but of the design of abstract data types.

Java is certainly less complex than C++. For example, it offers no templates, no operator overloading and no type coercion operators. However, although Java is apparently easier to use, it is far less elegant than C++ when it comes to creating user-defined types. Class interfaces in Java are usually much more verbose than similar interfaces in C++. And, due to the absence of templates, type casts are necessary in many places. On the other hand, casts in Java are type safe.



(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.