Journal Articles

CVu Journal Vol 14, #4 - Aug 2002 + Programming Topics
Browse in : All > Journals > CVu > 144 (17)
All > Topics > Programming (877)
Any of these categories - All of these categories

Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.

Title: Some Personal Reflections on C++ and Java

Author: Administrator

Date: 03 August 2002 13:15:54 +01:00 or Sat, 03 August 2002 13:15:54 +01:00

Summary: 

Body: 

I worked for a while last year on a project which used both C++ and Java and thought some of my experiences in this project might be of interest to others.

There were three of us on the team - one was a Java enthusiast, the other was happier with C++ than Java and I didn't have a particularly strong brief either way. The design phase was somewhat intriguing - we had little difficulty with the high-level architecture - deciding how to split the activity into a set of processes running on various machines and coming up with a simple inter-process communication method. The part we argued over more was which language to use for implementing each process!

Life might have been simpler if we'd stuck with one language, but there were good reasons for wanting a mix.

Which is the best tool for the job?

Deciding what is the 'best language' is a hard question to answer in the general case! Some of the factors which affect the choice of programming language for a given task are:

  • the skills you have on the development team

  • the likely skills available for maintenance

  • what other components you already have and/or need to use

  • licence costs (development environment/runtime)

  • customer preferences

  • performance requirements

  • reliability

  • development time

not forgetting the other, less acknowledged, factors which are part of most decisions:

  • choice by default - didn't realise there were options

  • prejudice

  • looks good on the CV

  • more 'exciting' technology

  • and I'm sure you can think of others...

In some of our cases the choice was obvious - for example we wanted to write some Web server code and Java servlets were a good fit. In other cases we required high performance, and had a gut feeling that C++ gave us more control over this than Java - we certainly had more experience between us in optimising C++ code rather than doing the same for Java code.

However in some cases there was no clear winner, so the person doing the first piece of coding for the process got to choose which language to use!

Coding with two hats on

What is different when you are writing code in two languages? First of all, each of us tended to have a 'preferred' language and found the other language slightly harder to program. For this reason it was a good idea to keep away from the more complicated parts of each language - we didn't use templates in C++ for example.

We also found that by keeping to "common ground" between C++ and Java it was possible to share common algorithms between the languages.

The main difficulties were of course the minor syntactical differences between the languages. The compiler catches most of these, although they are still a bit of a pain, but unfortunately the compilers don't help two particular cases so you just have to try and write (and read) the code with your brain fully engaged.

The first problem was string comparisons. C++ programmers tend to write this:

string s;
string t;
if( s == t ) {
  ...
}

which is of course perfectly OK in C++, thanks to operator overloading, but then translate it into Java as:

String s;
String t;
if( s == t ) {
...
}

which is not going to work in general since, as any Java programmer knows, this just checks the s and t refer to the same actual object and not whether the string values are the same. The Java version for the test would be

if( s.equals(t) )

To make matters worse, sometimes the equality test will work in Java - the String class keeps an internal list of so called canonical string objects. These are used for all string literals and constant strings - and may be also used by the programmer via the intern() method of the String class. For String objects from this list, if s.equals(t) is true then so is s==t.

The other problem - in the other direction - was with throwing exceptions. A Java programmer writes:

throw new MyException( "Error" );

together with

try
  ...
catch ( MyException ex )

and thinks nothing of it. However, if the programmer writes the same code in C++ it will compile without warning and run without apparent error - but not do what is expected when the exception actually gets thrown!

Why not? Well, in the Java world the exception is a reference to a MyException object, but in the C++ world it is a pointer to a MyException object and so the catch statement won't match the type of the thrown object.

There is a second problem too in the C++ code - the exception is being caught by copy and if the actual exception thrown were from a derived class this extra information would be lost.

It is important to ensure the C++ code looks like:

throw MyException( "Error" );

together with

try
  ...
catch ( MyException & ex )

This is a hard problem to find - like nearly all problems in exception handling - because the problem only arises when you have an exception. So you then have two problems - firstly (since the exception is not being handled properly) the program typically just aborts, and secondly you still have to find the cause of the original exception. When the exception is caused by a condition that is hard to reproduce it can waste a lot of debugging time. This was one of the places where Java wins hands down over C++ - firstly because the compiler checks the right sort of object is being thrown and secondly because Java exceptions have built in stack tracing and often just printing the stack trace at the top level of the program was enough to find and fix the problem.

Build problems

I always expected C++ would be hard (all these link time dependencies, incompatible compiler settings, etc) but we had more problems with our Java code.

Java code is compiled in one environment (with one set of class libraries) and then executed in a potentially different environment. Programs typically do not start if class files are missing at runtime - which is bad enough but at least it is a fairly easy problem to fix.

A worse problem occurs when a class file found at runtime does not match the class file used to compile the code. Since Java resolves method calls at runtime, the problem usually only shows itself when a missing or changed method is called - producing a runtime exception and the death of the program.

This caused us problems with JAR files too - the order of JAR files on the class path becomes critical if there are any duplicate class files. We discovered that 3rd party JAR files sometimes include a snapshot of a specific version of some Java interface or class - in particular some of the javax.xml packages seemed to get around a lot...

We found that, having statically linked all our C++ programs, we needed to more care in setting up the runtime environment for Java than for C++.

Integration Testing

We neared the end of our first round of development and reached the point where all the processes could be linked together and the system as whole was ready to test.

I was quite surprised with what we found when we started our testing!

Firstly, memory leaks. Now everyone knows C++ tends to leak ... so did we. Hence we'd avoided using raw pointers in C++ code and used other techniques - standard library collections, auto pointers, reference counted pointers. We were pleased with the result - our C++ programs barely leaked any memory.

Unfortunately we had a leak in one of our Java programs. We found this quite a challenge - it is much harder to poke around with low level memory management in Java than in C++ and the indeterminate nature of garbage collection made it quite hard for us to track down the problem. Eventually we discovered that we were creating a pair of socket objects for inter-process communication and one object was left blocked on a read when the underlying connection was broken.

As other articles and talks by ACCU members in recent months have pointed out, having a garbage collector does not solve all your resource problems. Well-crafted C++ can do as good a job in many cases - and has the added advantage that the C++ destructor is called at a known time in the life of the program.

Secondly, performance. Somewhat to my shock we had more performance problems with our C++ code than with our Java code. After we'd all talked about this for a while (and generated rather more heat than light) we eventually put in some instrumentation and started to measure things.

We used the Windows 2000 high resolution timer (and wrote a very simple native interface to allow us to access it from Java) to measure key parts of our program execution.

Unsurprisingly we found parsing and generating XML strings was expensive. On more investigation discovered our C++ compiler's implementation of std::string always increased the size of the underlying buffer by a fixed amount and so creating large strings took abnormally long times.

What options did we have?

One option was to use another standard library - STLport for example. We had a reluctance to abandon the implementation bundled with the compiler, for a variety of reasons which may or may not have been completely rational, and instead looked at optimising our XML generation.

We realised that by executing the XML generation code twice we could make it faster!

The first time through we simply counted the number of characters and didn't write anything; the second time through we actually wrote the data. In between the two calls we could allocate a string of the required size (using the "reserve" method) thereby guaranteeing it never had to grow.

It worked like a champ - and of course similar algorithmic changes could also improve the performance of the Java code.

Improving the algorithm was better than trying to optimise the memory allocation.

Conclusion

It was an interesting experience working interchangeably with two languages. We had a few problems which I've outlined but in general I liked the flexibility. We were able to use each language where it fitted well, and so, for example, could use 3rd party components where they were available in one language but not the other.

Although Java and C++ have similar syntax the same programs, written in the two languages, are often radically different. Fortunately they are a flexible enough pair of languages that it is possible to support a programming style which 'makes sense' to practitioners in both languages.

It is easy to make assumptions about the two languages - and it is important to be aware of this. C++ is capable of high performance, and Java does have a garbage collector - but this should not be an excuse for my laziness in assuming it will work without effort!

Notes: 

More fields may be available via dynamicdata ..