Java considered harmful (for programming C++)

Java coders trying to code in C++

As I explain in my other java page, I'm not very fond of the language for several reasons. This "second part" examines a bit how Java teaches bad habits to Java coders who then try to code something in C++.

When Java was designed, some inspiration was taken from C++ thus making Java similar to it in many aspects. Many syntactical details are identical or at least very similar (which gives one the feeling that they tried to make a "better C++" instead of just developing a whole new language) which makes both languages resemble each other.

I consider this a rather bad idea, specially from the point of view of someone who is fluent in Java but does not know too much about C++ and wants to (or has to) make a C++ program. Regardless of their resemblance, Java and C++ are two completely different languages and they should be approached differently; what is a good idea in one language may be a bad idea in the other. Too few people realize this fact.

Java often forces the programmer to do things in Java which are often a rather bad idea in C++. Usually there's a much simpler, easier and safer way of doing those things in C++.

Here I present two actual examples of C++ code written by Java programmers. Type, variable and function names have been changed for the sake of anonymity, and I have also added or removed whitespace for proper clearer indentation where necessary, but otherwise these are genuine unmodified pieces of code.

I love new!

The most typical problem with Java coders trying to program in C++ is that they are too infatuated with 'new'. Here's a typical example:

class AType
{
    int a, b, c;
    [SNIP]
};

class AContainer { [SNIP] };

class DerivedContainer1: public virtual AContainer
{
public:
    [SNIP]

    DerivedContainer1(const AType& i,const AType& e,
                      const SomethingElse& value) : AContainer(value)
    {
        var1_ = new AType(i);
        var2_ = new AType(e);
    }

    [SNIP]

private:
    AType* var1_;
    AType* var2_;
};

typedef list<AContainer*> ContainerList;

class DerivedContainer2: public virtual AContainer
{
public:
    DerivedContainer2()
    {
        thelist_ = new ContainerList();
    }

    [SNIP]

private:
    ContainerList* thelist_;
};

In other words, the program:

  1. Allocates dynamically two instances of 'AType' to the two pointers in 'DerivedContainer1'. There was absolutely no reason why these could have not been direct member variables ('AType' contains just a couple of ints).
  2. Allocates dynamically a list containing pointers to 'AContainer' inside 'DerivedContainer2'. Also here there was absolutely no reason why the list could not be a direct member variable of the class.
  3. Allocates each element of this list dynamically in this same class. In this program all the instances were of type 'DerivedContainer1' and none of any other type (by program specification). There was no reason why the list could not contain instances of 'DerivedContainer1' directly.
  4. Allocates an instance of 'DerivedContainer2' dynamically (when there was no reason to do so). Only one instance was necessary in the program and there was absolutely no reason to allocate it dynamically.
  5. Lacks proper copy constructors and assignment operators for 'DerivedContainer1' and 'DerivedContainer2'.
  6. Needlessly uses virtual inheritance, adding needless overhead to the generated code.

In principle it was not wrong for the program to be prepared to contain more than one derived type in that list, but in this specific case it was completely unnecessary. In any case, allocating the 'AType', the list and the 'DerivedContainer2' instances dynamically was completely unnecessary.

This same program also had lots of member functions which returned pointers to objects dynamically allocated by the function itself, in a very Java style. These functions were public and called from other classes (that is, the responsibility of freeing those objects was transferred to them). There was, naturally, no good reason for the functions to do this.

Not surprisingly this program had quite many memory leaks even though it tried to delete everything it allocated.

I love the Java way!

Somehow some Java coders seem obsessed in doing things a lot more complicated than they really are:

void AClass::transform( double x, double y, double z ) {

  Point* tmp = new Point( x, y, z );

  TransformationMatrix* matrix = new TransformationMatrix( tmp );

  if( Transformations ) {
    Transformations->multiply( *matrix );
    delete matrix;
    matrix = NULL;
  } else {
    Transformations = matrix;  
  }

  delete tmp;
  tmp = NULL;

  return;
}

The 'Transformations' member variable is a pointer to a dynamically allocated object of type 'TransformationMatrix'.

With a very minor modification in that class, 'Transformations' could be a direct member variable and this function could be written as:

void AClass::transform( double x, double y, double z )
{
  Transformations.multiply(Point(x, y, z));
}

This is a lot simpler, easier, more intuitive, safer and probably quite more efficient (the compiler can probably optimize a static instance quite a lot better than a dynamically allocated one).

Consequences

It's quite clear that, from the point of view of C++ programming, Java teaches very bad habits. I believe that many Java programmers don't even fully understand what 'new' does (either in Java or C++). Many probably think that it's just mandatory syntax to tell that "this is an object of type that", that it doesn't really do anything but is just mandatory syntax (in a similar way that eg. 'function' is typically a mandatory syntax in many languages to start the definition of a function: It doesn't really do anything but to tell the compiler that "a function definition follows").

In Java you have no choice: You either create objects dynamically with 'new' or you don't. There's no other way. Everything is created this way.

The big problem is that when many Java coders try to make a C++ program they think C++ works in the same way: Everything has to be created with 'new'. Since you can do so, and it compiles and it seems to work, they simply do so.

But then the problems start to show up. C++ is not Java, and what is natural in Java is often a rather bad idea in C++, and the excessive use of 'new' is one such thing. In Java you are forced to use it, in C++ you should not use it unless it's absolutely necessary and you know what you are doing.

Java programmers will then typically diss C++ because of this. They will argument that they can freely and safely do this in Java without problems and that C++ sucks because they can't, but they stumble accross tons of problems because of having to call 'delete' for each one, they have to be careful with copy constructors and assignment operators, etc etc.

Ok, fair enough: That is one of the weaknesses of C++: Handling dynamically allocated memory requires experience and care and should not be done lightly.

However, the problem is that more often than not you don't have to use 'new' at all! Unlike in Java, you can create local instances of classes which lifetime is very well defined, and you have standard data containers which are there so that you don't have to allocate things yourself (most of the time the standard data containers will securely handle allocations and deallocations themselves behind the scenes).

There are many advantages in using local instances and data containers: The code will become simpler, easier to understand, easier to write, a whole lot more secure and more efficient (both speedwise and memorywise). However, unfortunately Java teaches all the bad habits which should be avoided in C++.