Marco Cantu先生的一篇探讨Java,C++与Object Pascal的文章,很不错。
[h2]Comparing OOP Languages:Java, C++, Object Pascal[/h2]
--------------------------------------------------------------------------------
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'lldo
on comparing it in the three
languages. I won't show you how to use these language features in actual examples.
Ido
n't want to teach you OOP, only to compare these languages.
[h3]Key OOP Features [/h3]
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.
[h3]Compile-Time vs. Runtime Type Checking [/h3]
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 todo
most if not all of the type checking at
runtime.
[h3]Hybrid vs. Pure OOP Languages [/h3]
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).
[h3]Plain Object Model vs. Object Reference Model [/h3]
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.
[h3]Classes, Objects, and References [/h3]
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, butdo
es
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.
[h3]The Recycle Bin [/h3]
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.
[h3]Defining New Classes [/h3]
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 thedo
t 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.
[h3]Constructors [/h3]
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.
[h3]Destructors and finalize() [/h3]
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.
[h3]Class Encapsulation (Private and Public) [/h3]
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.
[h3]Files, Units, and Packages [/h3]
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++ compilerdo
esn'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 compilerdo
esn't
enforce. This means that the linker has a lot of work todo
, 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. Thisdo
esn't require the extra work of set up namespaces, but it's
built in the languages.
[h3]Class/Static Method and Data [/h3]
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
[h3]Classes and Inheritance [/h3]
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:
classdo
g: 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
do
g = 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.
classdo
g 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.
[h3]The Mother of All Classes [/h3]
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++ languagedo
esn'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
begin
ning, 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 todo
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 youdo
n't need the functionality of a base class
you probably should not inherit from it!
[h3]Subtype Compatibility [/h3]
Feature: Not all the OOP languages are strongly types, as I mentioned at the begin
ning,
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.
[h3]Late Binding (and Polymorphism) [/h3]
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 whichdo
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 Ido
n'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.
[h3]RTTI [/h3]
Feature: In strongly typed OOP languages the compilerdo
es 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 thedo
wncast) 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 ofdo
wncast (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 anddo
wncast 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-safedo
wncast 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.0do
esn'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-safedo
wncast 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 asdo
g;
[h3]Exceptions Handling [/h3]
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.
[h3]Templates (Generic Programming) [/h3]
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.
[h3]Other Specific Features [/h3]
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 languagedo
n'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
typicallydo
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 thatdo
esn'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, youdo
n'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.
[h3]Standards [/h3]
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.
[h3]Conclusion: Languages and Programming Environments [/h3]
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!