Marco's Web Center

Menu for Development

Site Menu
Object Pascal Handbook
Delphi Handbooks Collection
Mastering Borland Delphi 2005
(Old) White Papers
(Old)Tools
(Old) Conferences

My Other Sites
Italian Site (www.marcocantu.it)
the delphi search

Spirit of delphi

Advertising
Home My Blog Books Object Pascal Marco

Home: Development: Papers

Comparing OOP Languages:
Java, C++, Object Pascal

This text is a work in progress: suggestions and corrections are welcome. This paper is copyright Marco Cantù 1997-99 and cannot be distributed without permission. Last updated on November 15th 1997.


Java is a popular Internet language, C++ used to be the most common OOP language, and Object Pascal is the language Borland uses inside Delphi. Although this is not immediately evident, these three languages have many things in common. The aim of this presentation is to delve into technical aspects of the three languages, comparing them. I'm not trying to assess which is the best language, because this largely depends on what you want to use it for.

This presentation requires a minimum knowledge of one of the OOP languages discussed, or at least a basic knowledge of OOP concepts in general. I'll just describe why a certain language feature is important, then I'll do on comparing it in the three languages. I won't show you how to use these language features in actual examples. I don't want to teach you OOP, only to compare these languages.

Key OOP Features

Object-Oriented Programming (OOP) is not a new programming technique. Its roots date back to Simula-67, although its first complete implementation relates to Smalltalk-80. OOP became popular in the second part of the of the 80ies, with so diverse languages as C++, Objective-C (another extension of C), Object and Turbo Pascal, CLOS (an OOP extension of Lisp), Eiffel, Ada (in its last incarnations), and more recently Java. In this presentation I'll focus only on C++, Object Pascal and Java, with limited references to other OOP languages.

The key OOP features are well know, and I'm covering them only to be able to use a common terminology with you, before we proceed.

  • The first key feature is the definition of classes, abstract data types which encapsulate their representation, and make available some operations, or methods. Classes are usually the basis of modularity, encapsulation, and data abstraction in OOP languages.
  • The second key feature is inheritance, a way to define a new type inheriting the elements (representation and methods) of an existing one and modifying or extending it. This favors the expression of specialization and generalization.
  • The third feature is known as polymorphism, and allows you to refer to objects of different classes (usually within a sub-hierarchy) in a homogeneous way. This makes the classes even more reusable, the programs more easy to extend and maintain.

Classes, inheritance, and polymorphism are fundamental features required by a languages to be described as an OOP language. (Languages not having inheritance and polymorphism, but only classes, are generally indicates as class-based). Having said this, different OOP languages follow completely different approaches. We can discriminate among different OOP languages comparing type checking mechanisms, the ability to support different programming models, and the object model they support. Then I'll move to specific language features.

Compile-Time vs. Runtime Type Checking

Programming languages can be evaluated rating how much "strongly-typed" they are. The checks on the type relate to the existence of the methods being called, the types of their parameters, the array range checks, and so on.

C++, Java, and Object Pascal all favor compile-time type-checking, more or less extensively. Of the three C++ is probably the less precise, and Java the one enforcing type checking at the highest extent. The reason is that C++ maintains compatibility with the C languages, which supports compile-time type-checks, but in a very light way. For example C and C++ consider the arithmetic type as being all compatible (although when assigning a float to an int the compiler issues a warning). In Object Pascal and Java a Boolean value is not an integer, and a characters is another different and incompatible type.

The fact that the Java virtual machine "interprets" the byte-code at runtime, doesn't mean that the language gives up the compile-time type-checking. On the contrary, in this language the checking is more thorough. Other OOP languages as Smalltalk and CLOS, instead, tend to do most if not all of the type checking at runtime.

Hybrid vs. Pure OOP Languages

Another differences in among pure and hybrid OOP languages. Pure OOP languages are those allowing only one programming model, OOP. You can declare classes and methods, but you cannot have plain old functions and procedures, and global data.

Among our three languages, only Java is a pure OOP language (as Eiffel and Smalltalk are), which at first seems a very positive idea. However, you end up using a lot of static methods and static data, which is not that different from using global functions or data, beside the more complex syntax. In my opinion pure OOP languages offer an advantage for OOP newcomers, because programmers are forced into using (and learning) the object oriented programming model. C++ and Object Pascal, instead, are two typical example of hybrid languages, which allow programmers to use traditional C and Pascal programming approaches.

Notice that Smalltalk extended this concept of having only objects up to the level of defining as objects also the predefined data types, as integers and characters, and the language constructs (as the looping instructions). This is theoretically interesting, but reduces the efficiency quite a lot. Java stops much earlier, allowing the presence of native, non OOP, data types (although there are wrapper classes for the native types).

Plain Object Model vs. Object Reference Model

A third element discriminating OOP languages is their object model. Some traditional OOP languages allow programmers to create objects on the stack, the heap and the static storage. In these languages a variable of a class data type corresponds to an object in memory. This is how C++ works.

Lately, there seems to be a trend to use a different model , called object reference model. In this model every object is allocated dynamically on the heap, and a variable of a class type is actually a reference or a handle to the object in memory (technically something similar to a pointer). Java and Object Pascal both adopt this reference model. As we'll see in a while this means that you should remember to allocate memory for the object.

Classes, Objects, and References

  • Feature: Since we are discussing OOP languages, after this introduction, the starting point is to discuss classes and objects. I hope everyone clearly understands the difference between these two terms: in short, a class is a data type, an object is an instance of a class type. Now how to we use objects in languages using different object models?

  • C++: In C++, if we have a class MyClass with the method MyMethod, we can write
    MyClass Obj;
    Obj.MyMethod();

    and get an object of the MyClass class named Obj. The memory for this object is typically allocated on the stack, and you can start using the object right away, as in the second line above.

  • Java: In Java a similar instruction allocates only the memory space for the handle to the object, not for the object itself:
    MyClass Obj;
    Obj = new MyClass();
    Obj.MyMethod();

    Before you use the object, you have to call new to allocate the memory for the object. Of course, you should declare and initialize the object with a single statement whenever possible, to avoid using un-initialized objects handles:

    MyClass Obj = new MyClass();
    Obj.MyMethod();

  • OP: Object Pascal has a very similar approach, but requires different statements for the declaration and the initialization:
    var 
      Obj: MyClass;
    begin 
      Obj := MyClass.Create; 
      Obj.MyMethod;

  • Note: If the object reference model seems to require more work for the programmer, keep in mind that in C++ you often have to use pointers to objects and references to objects. Only using pointers and reference for example, you can get polymorphism. The object reference model, instead, makes the pointers the defaults, but does a good job hiding them. In Java, in particular, there are officially no pointers, but pointers are everywhere. Only programmers have no direct control over them, so that they cannot access random memory locations, for security reasons.

The Recycle Bin

  • Feature: Once you have created and used an object you need to destroy it, to avoid using unnecessary memory.

  • C++: In C++ destroying objects allocated on the stack is fairly simple. Handling the destruction of object allocated dynamically, on the other hand, is often a complex issue. There are many solutions including reference counting and smart pointers, but this is far from a simple issue. The first impression for C++ programmers is that using a reference object model makes the situation even worse.

  • Java: This is certainly not the case with Java, since the virtual machine runs a garbage collection algorithm in the background. This is something programmers get for free, but something that might adversely affect the performance of applications. Not having to write destructors may lead to logical errors in the cleanup code.

  • OP: Object Pascal, instead, has no garbage collection mechanism. However Delphi components support the idea of an owner object: the owner becomes responsible for destroying all the object is owns. This makes handling the object destruction very simple and straightforward.

Defining New Classes

  • Feature: Now that we've seen how to create objects of the existing classes, we can focus on the definition of new classes. A class is simply a collection of methods, operating on some local data.

  • C++: This is the C++ syntax of a simple class definition:
    class Date {
      private: 
    	int dd; 
    	int mm; 
    	int yy;
      public:
        void Init (int d, int m, int y);
    	int Day ();
    	int Month ();
    	int Year ();
    };

    And here is the definition of one of the methods:

    void Date::Init (int d, int m, int y)
    { 
      dd = d;
      mm = m;
      yy = y;
    }
  • Java: Java syntax is very similar to C++ syntax:
    class Date { 
    	int dd = 1; 
    	int mm = 1; 
    	int yy = 1;
    	public void Init (int d, int m, int y) { 
    		dd = d; mm = m; yy = y; }
    	public int Day () { return dd; }
    	public int Month () { return mm; }
    	public int Year () { return yy; }
    }

    The biggest difference is that the code of each method is written directly when it is declared (without making the function an inline function, as happens in C++), and that you can initialize the data members of the class. Actually if you fail do to so Java initializes all the data members for you, using a default value.

  • OP: In Object Pascal the syntax of the class declaration is different, and more similar to C++ than to Java:
    type 
      Date = class 
      private 
        dd, mm, yy: Integer; 
      public 
        procedure Init (d, m, y: Integer); 
        function Month: Integer; 
        function Day: Integer; 
        function Year: Integer; 
      end;
    
    procedure Date.Init (d, m, y: Integer);
    begin 
      dd := d; 
      mm := m; 
      yy := y;
    end;
    
    function Date.Day: Integer;
    begin 
      Result := dd;
    end;

    As you can see there are syntactical differences: methods are defined with function and procedure keywords, the methods without parameters have no parenthesis, methods are simply declared inside the class definition, then defined later on, as usually happens in C++. However, Pascal uses the dot notation, while C++ relies on the scope operator (an operator not available in Object Pascal and Java).

  • Note: Accessing to the current object. In OOP languages method are different from global functions because they have an hidden parameter, a reference or pointer to the object we are operating on. This reference to the current object simply takes a different name. It is this in C++ and Java, self in Object Pascal.

Constructors

  • Feature: The above class is terribly simple. The first thing we can add to it is a constructor, which is a good technique for solving the problem of objects initialization.

  • C++: In C++, as in Java, constructors have the same name of the class. If you don't define any constructor the compiler synthesizes a default constructor, adding it to the class. In both these languages you can have multiple constructors thanks to methods overloading.

  • Java: Everything works as in C++, although constructors are also called initializers. This highlights the fact that is the Java virtual machine to create the objects, while the code you write in a constructor simply initializes the newly created object. (The same actually happens also in Object Pascal.)

  • OP: In Object Pascal you use a specific keyword, constructor. In this language there is no method overloading, but since constructors have custom names name, you can provide several constructors with different names. In this language each class has the default Create constructor, unless you override it with a constructor having the same name and eventually different parameters. This constructor is simply inherited by a common base class, as we'll see later on.

Destructors and finalize()

  • Feature: A destructor has the opposite role of a constructor, and is generally called when an object is destroyed. If most classes need a constructor, only few of them need a destructor. A destructor should basically free resources allocated by the constructor (or by other methods during the life of the objects). These resources include memory, files, database tables, Windows handles, and so on.

  • C++: C++ destructors are automatically called when an objects goes out of scope, or when you delete a dynamically allocated object. Every class can have only one destructor.

  • OP: Object Pascal destructors are similar to C++ destructors. Object Pascal uses a standard virtual destructor, called Destroy. This destructor is called by the standard Free method. All objects are dynamic, so you are supposed to call Free for each object you create, unless it has an owner responsible for its destruction. In theory you can declare multiple destructors, which makes sense because you call destructors in your code (there is nothing automatic).

  • Java: Java has no destructors. Objects without references are destroyed by the garbage collection algorithm, which runs as a background task. Prior to destroying an object the garbage collector calls the finalize() method. However there is no guarantee that this method is actually called (at least in Java 1.0). For this reason if you need to free resource you should add a custom method, and ensure it is called.

Class Encapsulation (Private and Public)

  • Feature: A common element of the three language is the presence of three access specifiers indicating different levels of class encapsulation, public, protected, and private. Public means visible by every other class, protected means visible by derived classes, private means no external visibility. The details, however, are different.

  • C++: In C++ you can use the friend keyword to by pass encapsulation. The default visibility for a class is private, for a struct is public.

  • OP: In Object Pascal, private and protected have effect only for classes in different units. A class is friend of every other class declared in the same unit (or source code file). Delphi has two more access specifiers, published and automated. Published generates RTTI information for the element, automated an OLE Automation interface.

  • Java: In Java, a syntactical difference is that access specifiers are repeated for every class member. A more concrete difference is the default in Java is friendly, which means the element is visible also by other classes of the same package (or source code file, similarly to what happens in OP). Similarly, the protected keyword indicates the visibility to subclasses, but also to other classes of the same package, while the private protected combinations corresponds to C++ protected.

Files, Units, and Packages

  • Feature: An important difference between the three languages is the organization of the source code in files. All three languages use files as standard mechanism for storing the source code (differently from other OOP languages, as Smalltalk), but while the C++ compiler doesn't understand files, the OP and Java compilers do. Both languages work with the idea of module, although the concept assumes a different name.

  • C++: In C++, programmers tend to place class definitions in header files, and method definitions in separate code files. Usually the two files have the same name and a different extension. A compilation unit generally refers (includes) its own declaration file plus the declaration files for the classes (or functions) the code refers to. These are all conventions the compiler doesn't enforce. This means that the linker has a lot of work to do, because the compiler cannot anticipate in which other module a method will be defined.

  • OP: In Object Pascal, each source code file is called unit, and is divided in two parts, the interface and the implementation, marked by these two keywords. The interface section includes the definition of the class or classes (with the declaration of the methods), and the implementation section must include the definition of the methods declared in the interface. It is illegal to write actual code in the interface section. You can refer to the declaration in another file with a uses statement. This includes the interface of that file in the compilation:
    uses
      Windows, Form, MyFile;

  • Java: In Java, each source code file, or compilation unit, is compiled separately. You can then mark a group of compilation units as being part of a single package. Differently than the other two languages, you write all of the code of the methods as you declare the class. When a file is included, with an import statement the compiler reads only its public declarations, not all of its code:
    import where.myclass;
    import where.* // all the classes

  • Note: Modules as name spaces. Another important difference is that Java and OP compilers can read a compiled file and extract its definition, as it you were extracting the header file from the compiled code. As an aside, the C++ language introduced namespaces to overcome the absence of a module structure. In Java and OP, in fact, when two names clash, you can generally prefix the name with the module name. This doesn't require the extra work of set up namespaces, but it's built in the languages.

Class/Static Method and Data

  • Feature: OOP languages generally allow to have some methods and data which relates to the class as a whole, not to specific objects. Class method generally can be called both for an object of the class or applied to the class type as a whole. Class data is data not replicated for each object, but shared among them.

  • C++: In C++ class method and data are indicated by the static keyword. Class data must be initialized with a specific declaration: this is one of the drawbacks of the absence of modules.

  • OP: OP has only class method, which are indicated by the class keyword. Class data can be replaced by adding a private global variables to the unit which defines the class.

  • Java: Java uses the same keyword of C++, static. Static methods are used very often (and even overused) because of the absence of global functions. Static data can be directly initialized in the class declaration

Classes and Inheritance

  • Feature: Inheritance among classes is one of the foundations of OOP. It can be used to express generalization or specialization. The basic idea is that you define a new type extending or modifying an existing type, in other words a derived class has all of the data and methods of the base class, plus new data and method, and eventually modifies some of the existing methods. Different OOP languages have a different jargon for the mechanism (derivation, inheritance, subclassing), the class you inherit from (base class, parent class, super class), and the new inherited class (derived class, child class, subclass).

  • C++: C++ uses the keywords public, protected, and private to define the flavor of inheritance, and hide the inherited methods or data, turning them to private or protected. Although the public inheritance is the most used version, the default is private inheritance. C++ is the only of these three languages with multiple inheritance, as we'll see later on. Here is an example of the syntax:
    class Dog: public Animal { 
    	... 
    };

  • OP: Object Pascal uses no keyword to express inheritance, but a special syntax, adding the base class name within parenthesis. The language supports only what C++ calls public inheritance. OP classes have a common base class, as we'll see later on.
    type 
      Dog = class (Animal) 
        ... 
      end;

  • Java: Java uses the extends keyword to express the only kind of inheritance, which corresponds to public inheritance in C++. Java has no support for multiple inheritance. Java classes have a common base class, as we'll see later on.
    class Dog extends Animal { 
    	...
    }

  • Note: Base class constructors and initialization. Constructors of inherited classes have a complex structure both in C++ and Java. In Object Pascal this it is the programmers responsibility to initialize the base class. This topic is quite complex, so I've skipped it in this presentation. Instead I'll focus on the common base class, access to the base class, multiple inheritance, interfaces, late binding, and other related topics.

The Mother of All Classes

  • Feature: In some OOP languages every class has at least a default base class. This class, often called Object or something similar, has some basic capabilities shared by all classes. This base class, in fact, is the class from which all the other classes ultimately inherit. This is a common approach because it's what Smalltalk originally did.

  • C++: Although the C++ language doesn't have these feature, many application frameworks based on it introduce the idea of a common base class. MFC is a notable example, with its CObject class. Actually this made more sense at the beginning, when the language lacked features as templates (and even more when it lacked multiple inheritance.

  • OP: Every class automatically inherits from the TObject class. Since the language lacks multiple inheritance all the classes form a huge hierarchical tree. The TObject class can handle RTTI and has few other capabilities.

  • Java: As in OP, all the classes implicitly inherit from the Object class. Also in this language the common base class has limited capabilities.

Accessing Methods of the Base Class

  • Feature: When you write a method of a class, or override a method of the base class, you often need to refer to methods of the base class. If the method is redefined in the derived class, using its name you'll access to the new version. OOP languages have some techniques or keyword to solve this problem.

  • C++: In C++ you can use the scope operator (::) to refer to a specific class. You can access to the base class, but also to a class higher up in the hierarchy.

  • OP: Object Pascal has a specific keyword to do this, inherited. after this keyword you can write the name of the base class method you want to call, or (in certain circumstances) simply use the keyword to access to the corresponding base method.

  • Java: Java uses the super keyword to accomplish the same thing. In this language, but also in OP, there is no way to refer to another ancestor class. This might seem a limitation at first, but it allows to extend a hierarchy by adding intermediate classes. At the same time if you don't need the functionality of a base class you probably should not inherit from it!

Subtype Compatibility

    • Feature: Not all the OOP languages are strongly types, as I mentioned at the beginning, but the three we are focusing on all share these feature. This basically means that objects of different classes are not type-compatible. There is an exception to this rule: objects of derived classes are compatible with the type of their base class. (Notice: the reverse is not true.)

    • C++: In C++ the subtype compatibility rule is valid only for pointers and references, not for plain objects. In fact, different objects have difference sizes, so you cannot accommodate them in the same memory location.

    • OP: The subtype compatibility is available for every object, thanks to the object reference model. Moreover, all the objects are type-compatible with the TObject type.

    • Java: Java shares exactly the same model of Object Pascal.

    • Note: Polymorphism. Subtype compatibility in particularly important to obtain late binding and polymorphism, as described in the next section.

Late Binding (and Polymorphism)

  • Feature: When different classes of a hierarchy redefine a method of their base class, it is very powerful to be able to refer to a generic object of one of these classes (thanks to the subtype compatibility) and call a method, which results in a call of the method of the proper class. To accomplish this the compiler should support late binding, that is it should not generate a specific function call, but wait until runtime to determine the actual type of the object and the function to call.

  • C++: In C++ late binding is available only for virtual methods (which become slightly slower to call). A method defined as virtual in the base class maintains this feature when it is redefined (but only if the method signature matches). Plain, non-virtual methods, do not allow late binding, as in Object Pascal.

  • OP: In Object Pascal late binding is introduced with the virtual or dynamic keywords (the difference between the two is only an technical implementation difference). In derived classes redefined methods should then be marked with the override keyword (this force a compiler check on the method signature). This is a peculiar aspect of OP, and the rationale behind it is that this allows for more changes in the base class.

  • Java: In Java all methods use late binding, unless you explicitly mark them as final. Final methods cannot be redefined, and are faster to call. Also in Java writing methods with the proper signature is vital to obtain polymorphism. The fact that in Java the default is late binding, while in C++ the default is early binding is a clear sign of the different approach of the two languages: C++ at times sacrifices the OOP model to favor efficiency.

  • Note: Late binding for constructors and destructors. Object Pascal, contrary to the other two languages, allows to define virtual constructors. Virtual destructors, instead, are supported by all three languages.

Abstract Methods and Classes

  • Feature: When building a complex hierarchy, programmers often need to introduce methods in higher level classes, to obtain polymorphism, even if the methods are not jet defined for that specific abstraction. Beside leaving the method empty, many OOP language implement specific mechanism, as the definition of abstract methods, that is methods without an implementation. Classes having at least one of abstract method are often called abstract classes.

  • C++: In C++ abstract methods, or pure virtual functions, and are obtained appending the so-called pure specifier (=0) to the method definition. Abstract classes are simply classes with (or inheriting) one or more abstract methods. You cannot create an object of an abstract classes.

  • OP: Object Pascal uses the abstract keyword to mark these methods. Again, abstract classes are classes having or inheriting abstract methods, but you can create an instance of an abstract class (although the compiler emits a warning message). This exposes a program to the risk of calling an abstract method, an event that generates a runtime error and terminates the program.

  • Java: In Java both abstract methods and abstract classes are marked with the abstract keyword (actually in Java it is compulsory to define as abstract a class which has abstract methods--although this seems a little redundant). Also derived classes which do not redefine all of the abstract methods must be marked as abstract classes. As in C++, it isn't possible to create instances of abstract classes.

Multiple Inheritance and Interfaces

  • Feature: Some OOP languages allow to inherit a class from more than one base class. Other language allow you to inherit only from one class, but optionally allow you to inherit also from multiple interfaces, or pure abstract classes, that is classes made only of pure virtual functions.

  • C++: C++ in the only of the three languages to support multiple inheritance. This is seen as a positive fact by some programmers, as a negative by others, and I don't want to start this discussion now. What is sure is that multiple and repeated inheritance brings along other concepts, as virtual base classes, which are not easy to master, although they are very powerful. C++ hasn't got the concept in an interfaces, although it is possible to replicate it with multiple inheritance from pure abstract classes (interfaces can be seen as a subset of multiple inheritance).

  • Java: Java, as Object Pascal, has no multiple inheritance, but has full support for interfaces. Methods of interfaces allow polymorphism, and you can use an object implementing an interface when an interface object is expected. A class can inherit from, or extend, one base class but can implement (this is the keyword) multiple interfaces. Although this wasn't planned in advance, Java interfaces map very well into the COM model. An example:
    public interface CanFly { 
    	public void Fly();
    }
    public class Bat extends Animal implements CanFly { 
    	public void Fly( ) { // the bat flies... }
    }

  • OP: Delphi 3 has introduced in Object Pascal has a concept similar to Java interfaces, but these interfaces are strongly mapped to COM (although it is technically possible to use them in plain non-COM programs). Interfaces form a hierarchy separated from classes, but as in Java a class can inherit from a base class and implement several interfaces. The mapping of the methods of the class into the methods of the interfaces the class implements is one of the more convoluted parts of the Object Pascal language.

RTTI

  • Feature: In strongly typed OOP languages the compiler does all the type-checking, so there is little need to keep information about classes and types in the running program. However there are cases (as the downcast) which require some type information. For this reason all the three OOP languages we are examining support Runtime Type Identification/Information (RTTI, in both cases) to a higher or lesser extent.

  • C++: The C++ language originally had no support for RTTI. It was later added in the form of downcast (dynamic_cast) and making available some type information for classes. You can ask type identification for an object, and check if two objects are of the same class.

  • OP: Object Pascal and its visual environment support and require a lot of RTTI. Not only are type checking and downcast available (with the is and as operators), but classes generate extensive RTTI for their published elements. Actually this keyword governs part of the RRTI generation. All the idea of properties, the streaming mechanism (the form files), and the Delphi environment, starting from the Object Inspector, rely heavily on class RTTI. The TObject class has (among others) the ClassName and ClassType methods. ClassType returns a class type variable, an instance of a special class reference type (which is not a class itself).

  • Java: As in Object Pascal, also in Java having a single base class helps keeping track of class information. The type-safe downcast in this language is the default type conversion. The getClass() method of Object returns a sort of metaclass (an object of a class describing classes), and you can apply the getName() function to it to get a string with the class name. You can also use the instanceof operator. Java 1.0 doesn't include extensive RTTI for classes, but this should change in future releases, to favor the development of visual environments and components (the so-called Java Beans).

  • Example: Here is the syntax of the type-safe downcast in the three languages. IN case of an error each of the three languages raises an exception:
    // C++
    Dog* MyDog = dynamic_cast <Dog*> (myAnimal);
    // Java
    Dog MyDog = (Dog) myAnimal;
    // Object Pascal
    Dog myDog := myAnimal as Dog;

Exceptions Handling

  • Feature: The basic idea of exceptions handling is to simplify the error handling code of a program, providing a standard build in mechanism, with the goal of making programs more robust. Exceptions handling is a topic deserving a full presentation, so I'll just sketch some key elements and differences.

  • C++: C++ uses the throw keyword to generate an exception, the try keyword to mark a guarded block, and the catch keyword to write the exceptions handling code. Exceptions are generally object of special classes, possibly forming a hierarchy in all three languages. C++ performs stack unwinding, destroying (and calling destructors) for all of the objects on the stack.

  • OP: Object Pascal uses similar keywords, raise, try, and except, and has similar capabilities. The only real difference is that there is no stack unwinding, simply because there are no objects on the stack. As an alternative you can add a finally keyword, to indicate code that should always be executed, regardless of the fact that an exception has been raised or not. In Delphi exception classes are derived from Exception.

  • Java: Uses the C++ keywords, but has the same behavior of Object Pascal , including the extra finally keyword. This is common to all the languages with an object reference model. The presence of a garbage collection algorithm limits the use of finally to class which allocate resources other than memory. Java is also more rigorous in pretending that all the functions that can raise an exception have a proper exception clause indicating which exceptions the function can raise. This is checked by the compiler. This is a powerful technique, and is usually well regarded even if it implies more work for the programmer. In Java classes of exception objects must inherit from the Throwable class.

Templates (Generic Programming)

  • Feature: Generic programming is a technique for writing functions and classes leaving some data types unspecified. The type specification takes place when the function or class is used in the source code. Everything is strictly under the supervision of the compiler, and nothing is left to determine at runtime. The most typical example of template classes is that of container classes.

  • C++: Only C++ (of these three languages) has generic classes and functions, indicated by the template keyword. The C++ standard includes a huge template class library, called STL, which support a peculiar and powerful programming style.

  • OP: Object Pascal has no template. Container classes are generally built as containers of objects of the TObject class.

  • Java: Has no templates, as well. You can use containers of Objects, or resort to other tricks.

Other Specific Features

  • Feature: There are other features I've not covered, because they are not fundamental, and they are specific of only one language.

  • C++: I've already mentioned multiple inheritance, virtual base classes, and templates. This are features missing in the other two OOP languages. C++ has also operator overloading, while method overloading is present also in Java. C++ allows programmers to overload also global functions. You can overload also the type cast operators, writing type conversion methods that might be called behind the scenes. The C++ object model requires copy constructors and the overloading of assignment operators, something the other two language don't need, because they are based on an object reference model.

  • Java: Only Java supports multithreading right into the language. Objects and methods support synchronization mechanisms (with the synchonized keyword): two synchronized methods of the same class cannot be executed at the same time. To create a new thread you can simply derive from the Thread class, overriding the run() method. As an alternative you can implement the Runnable interface (this is what you typically do in an applet which supports multithreading). We've already discussed the garbage collector. Another key feature of Java, of course, it the idea of portable byte-code, but this is something that doesn't strictly relate to the language.

  • OP: Some special features of Object Pascal are class references, easy to use method pointers (which are the basic of the event model), and in particular properties. A property is just a name hiding the way you access the data of a method. A property can map to a direct read or write of data, or can refer to access methods. Even if you change the way the data is accessed, you don't need to change the calling code (although you have to recompile it): this makes property a very powerful encapsulation feature. Java is supposed to add this feature to the language in version 1.1, to support Java Beans.

Standards

  • Feature: Every language requires someone setting a standard, and checking that all the implementations conform to it.

  • C++: The ANSI/ISO C++ standard committee has almost finished a time-consuming standardization effort. Most of the compiler writers seems to try to comply with the standard, although there are still many peculiarities. In theory the development od the language has come to a stop. In practice, initiatives as the new Borland C++ Builder certainly make no good to the situation, but many feel that C++ badly needs visual programming environments. At the same time the popular Visual C++ stretches C++ in other directions, for example with a clear abuse of macro statements. My opinion is that each language has its own development model, and it makes little sense to try using a language for something it was not planned for.

  • OP: Object Pascal is a proprietary language, so it has no standard. Borland has licensed the language to a couple of small OS/2 compiler vendors, but this has had little impact. Borland is extending the language at each release of Delphi.

  • Java: Java is a proprietary language, too, and has even a trademark on the name. However Sun seems to be more than willing to license it to other compiler vendors. Sun is keeping control of the language and seems to be unwilling to have an official standardization body take care for it, at least for the moment. Sun is also trying to avoid the development of virtual machines which do not conform to the standard.

Conclusion: Languages and Programming Environments

    As I mentioned above, although I've tried to examine these language only comparing syntactical and semantic features, it is important to consider them in the proper context. These languages target different needs, are meant to solve different problems in different ways, and are used within highly different programming environments. Although both the languages and their environment are copying each other features, the were build with different needs in mind, and this is something you can see when comparing their features. C++ goal is power and control, at the expense of complexity; Delphi goal is easy, visual programming, without giving up to mush power, and strong connection with Windows; Java aim is portability, even giving up some of the speed, and distributed applications (or executable Web content).

    What can determine the success of these three languages are not their language features I have covered in this presentation. The financial status of Borland, the operating system control of Microsoft, the popularity of Sun in the Internet world (and the fact it is seen as the anti-Microsoft by some), the future of Web browsers and of the Win32 API, the role of ActiveX (and Delphi ActiveForms), are all factors which might affect your choices more than technical elements. For example a very nice language as Eiffel, from which both Object Pascal and Java have taken more than some inspiration, never got any real market share, although it has been popular in universities around the globe.

    Just keep in mind that "trendy" is becoming a common word in the computer world as never before. As users like to have this year model of toolbar (this is probably the reason OSes are named after the year the are released), programmers love working with the last programming language, and be the first to master it. We can say that "Java is not the last of the OOP languages", someone in the next few years will come up with a new trendy language, everyone will jump onto that bandwagon, thinking he cannot remain behind, and forgetting that most of the programmers in the world still type on their keyboard nice Cobol statement!

Author

Marco Cantù is author of books on two of the three languages discussed here, Object Pascal and C++, published in the US and many other countries. He writes (more or less regularly) for several magazines, and does training courses on OOP languages and on Windows programming with his company, WinTech Italia. He enjoys speaking at many conferences, worldwide. You can reach him on www.marcocantu.com.