TITLE: Java and C++. A Critical Comparison [ I included this "tip" for a change of pace. The tips will still be focused on C++, but I thought some of you might be interested in this. -adc ] (Newsgroups: comp.lang.c++.moderated) AUTHOR: "Robert C. Martin" , 17 June 96 Java and C++ A critical comparison Robert C. Martin 17 June, 1996 First of all, I want to make it very clear this is not a diatribe 'against' one language or another. I happen to like both Java and C++ quite a bit. I have been a long time programmer in C++, and have just begun to program in Java. I find programming in Java to be a joy. But then, I find programmin in any language to be a joy. This paper is simply a discussion of the differences in the two languages. I will not be commenting heavily upon deficiencies in C++. These are already very well documented (see Ian Joyner's famous critique of C++. For a copy write to: ian@syacus.acus.oz.au) I will, however, be commenting about both the good and bad points that I perceive in Java. When I have good things to say, this should not be taken as a recommendation of Java. By the same token, when I have bad things to say, this should not be taken as a admonition against the use of Java. In both cases, it is just me venting my opinion. Nothing more. Up front, I'll say that I am looking forward to writing lots of neat Java applications and applets. But that I am not going to give up C++ any time soon either. ----------------------------------------------------------------- Inheritance: ----------------------------------------------------------------- The designers of Java avoided multiple inheritance. Replacing it is multiple conformance to interfaces. In Java, there is a structure called an 'Interface'. A Java interface is almost identical to a C++ class that has nothing but pure virtual functions. In Java, you cannot inherit from more than one base class; even if the base classes have nothing but abstract methods (pure virtual functions). However you *can* "implement" more than one "interface"; which amounts to the same thing. Because interfaces cannot have implemented functions or data members, multiple implementation of interfaces does not lead to the problems that caused "virtual" inheritance to be added to C++. This is a good thing. In all likelihood it has simplified the language appreciably. However, there is a problem. It is often the case that we want to inherit from more than one base class which has functions and data. Consider the following C++ program which uses the Observer pattern. class Observer { public: virtual void Update() = 0; }; class Subject { public: void Register(Objserver& o) {itsObservers.Add(&o);} void Notify() { for (Iterator i(itsObservers); i; i++) (*i)->Update(); } private: Set itsObservers; }; class Clock { public: virtual void Tick() // called once a second to maintain the time. {itsTime++;} private: Time itsTime; }; class ObservedClock : public Clock, public Subject { public: virtual void Tick() {Clock::Tick(); Notify();} }; This last class shows where we would like to use multiple inheritance to Merge the Clock and Subject classes together. In Java one cannot do this. Rather one must do the following (I am winging the code here, and am not nearly as good at that as I am with C++; so expect some syntax errors.) public interface Observer { public void Update(); }; public interface Subject { public void Register(Observer o); public void Notify(); }; public class SubjectImpl implements Subject { public void Register(Observer o) { itsObservers.AddElement(o); } public void Notify() { Enumeration i = itsObservers.elements(); while(i.hasMoreElements()) { Observer o = (Observer) (i.nextElement()); o.Update(); } } private Vector itsObservers; }; class Clock { public void Tick() {itsTime++;} private Time itsTime; }; class ObservedClock extends Clock implements Subject { public void Tick() {super.Tick(); Notify();} public void Notify() {itsSubjectImpl.Notify();} public void Register(Observer o) {itsSubjectImpl.Regsiter(o);} private SubjectImpl itsSubjectImpl; }; This use of aggregation instead of multiple inheritance is inconvenient to say the least, especially when it must be used with a pattern that is a prevalent as Observer. This leads me to believe that the Java language will either need a more complete form of multiple inheritance, *or* it will need some new sytax that allows the compiler to automatically delegate. e.g. class ObservedClock extends Clock delegatesTo SubjectImpl.... This syntax would automatically cause ObservedClock to implement the interface of delegate as well as automatically forwarding all calls to that interface to an automatically contained sub object of SubjectImpl. ---------------------------------------------------------------------- Memory Management ---------------------------------------------------------------------- Java uses garbage collection. This is a very good thing. In most cases it frees the engineer from the problem of having to manage memory. C++ is often criticized for its lack of GC. However, many people have added garbage collectors to C++. These collectors are far from perfect, but they can be used when convenient. The corresponding statement cannot be made for Java. There is *no way* that this humble writer could discover to manage memory manually. Apparently, you cannot write your own memory manager and construct objects within the memory that it controls. Is this a problem? In most cases no. However, if Java is every really going to enter the real time market, discrete memory management will become a necessity. One cannot depend upon the vagaries of garbage collection when one must have submillisecond response time. One cannot simply follow James Gosling's advice when he says: "[Garbage Collection] can interfere with time critical applications. You should design systems to be judicious in the number of objects they create." Anyway, how hard could it be to put in a 'delete' keyword? I cannot believe that its omission can be maintained long term. ---------------------------------------------------------------------- Finalize ---------------------------------------------------------------------- The 'finalize' function in Java, coresponds to the destructor in C++. WHen an object is collected by the garbage collector, its finalize method is called. Apparently, upon normal exit, the garbage collector sweeps up all the uncollected objects, and their 'finalize' method is called at that time. (This implies that exitting can take a bit of time). However, there is a convention that one must adopt: class D extends B { protected void finalize() throws Throwable { super.finalize(); // now take care of business. } }; The 'finalize' of the derived class must *explicitly* call the 'finalize' of the base class. This is very error prone, and should have been taken care of by the compiler as in C++. ---------------------------------------------------------------------- toString ---------------------------------------------------------------------- Any class which has the toString method implemented as follows can be used in any context which expects a string. class MyClass { public String toString() { // convert myself to a String. } }; public void f(String s) { // do something with s. } MyClass c = new MyClass; f(c); // automatically invokes MyClass.toString(); This seems to be an immature version of the automatic conversion system of C++. This feature (among others) makes the String class something more special than any other class. I think it would be wise for the Java designers to work on a generic conversion system. (e.g. a to method template) ---------------------------------------------------------------------- exceptions and 'finally' ---------------------------------------------------------------------- I am very pleased with the exception mechanisms in Java. Although modeled after the C++ mechanisms, it avoids some of C++s more severe problems by using the 'finally' clause. In C++, when an exception leaves the scope of a function, all objects which are allocated on the stack are reclaimed, and their destructors are called. Thus, if you want to free a resource or otherwise clean something up when an exception passes by, you must put that code in the destructor of an object. This is artificial, error prone, and inconvenient. Moreover there are some really nasty issues having to do with throwing exceptions from constructors and destructors that make exceptions in C++ a difficult feature to use well. Now I am not going to claim that Java has fixed all these things. However, I like their solution better than the C++ solution. Every scope can have a 'finally' clause. Any time a scope is exitted, regardless of the reason for that exit (e.g. the function could simply return, or an exception could pass through it) the code in the finally clause is executed. Thus, cleanup code does not have to be artificially put into some destructor. IMHO, this makes Java exceptions much easier to use than C++ exceptions. I think the C++ community ought to take a good hard look at the Java solution. ---------------------------------------------------------------------- threads ---------------------------------------------------------------------- I am overjoyed with the way that threads have been implemented in Java. The implementation is minimal and elegant. They simple way that methods can be protected from concurrent update, the equally simple semaphore and critical code mechanisms, the very easy way of creating a rendezvous between two threads. This is a good feature. I can hardly wait to use it in anger. ---------------------------------------------------------------------- Standard Class Library ---------------------------------------------------------------------- Another joy is the standard class library. I'm not going to say it is perfect (I especially dislike the need to put hash functions in every object) but I must say that it has been enjoyable to use. It is nice having a bunch of standard resources at your fingertips. I wish the C++ community had adopted a standard much earlier. ---------------------------------------------------------------------- Conclusion ---------------------------------------------------------------------- This paper is far from complete. There are lots of other issue that I could talk about. I'll probably be updating this paper from time to time and I will repost it when I do. Comments and corrections are welcome.