Bruce Eckel’s recent blog post on the legacy left by C++ and Java generated a lot of reaction. While mentioning some design mistakes, he concludes that both languages have had a significant role in programming languages evolution and an important positive legacy. But is it not too early to talk about their legacy?
Eckel, a former member of the C++ Standards Committee, recollects the decision made regarding backward compatibility of the language with C from the beginning:
To understand how the language can be both unpleasant and complicated, and well designed at the same time, you must keep in mind the primary design decision upon which everything in C++ hung: compatibility with C. Stroustrup decided -- and correctly so, it would appear -- that the way to get the masses of C programmers to move to objects was to make the move transparent: to allow them to compile their C code unchanged under C++.
While C++ did succeed to attract most C developers to C++, the compatibility decision had a severe negative impact on language’s evolution:
This [compatibility with C] was a huge constraint, and has always been C++'s greatest strength ... and its bane. It's what made C++ as successful as it was, and as complex as it is.
For example, he acknowledges that operator overloading is difficult to use in C++:
They [those who did not understand C++ well enough] thought operator overloading was too hard for programmers to use properly. Which is basically true in C++, because C++ has both stack allocation and heap allocation and you must overload your operators to handle all situations and not cause memory leaks. Difficult indeed.
Of course, such statements are doomed to spark a debate. Archilleas Margaritis does not consider C compatibility should be an issue:
I don't think that C++ is badly designed because of compatibility with C. ADA is compatible with C, but it is a very good language, with strong engineering leading its design.
What is wrong with C++ is source code level compatibility with C. In order to be able to include C headers, C++ maintained the preprocessor system of C. That led to a strange non-context free grammar, which led to a very strange syntax which had to stay compatible with C.
Michele Costabirle considers that missing a standard library from the beginning was one of C++ flaws:
I think that one serious burden of C++ was the lack of a standard library.
If I recall it right, Stroustroup wrote in "The Design and Evolution of C++" that he delayed a standard library in favor of multiple inheritance. I would have enjoyed it more the other way.
Many things can be said regarding C++, but one thing is sure: C++ moved programmers one step up on the programming ladder.
Talking about a different language but on the same tone, Eckel reiterates some of the design mistakes done with Java:
For many years, the partly line from the Java team was "Operator overloading is too complicated." This and many other decisions where someone clearly didn't do their homework is why I have a reputation for disdaining many of the choices made by Gosling and the Java team. …
Primitives "had to be included for efficiency." The right answer is to stay true to "everything is an object" and provide a trap door to do lower-level activities when efficiency was required (this would also have allowed for the hotspot technologies to transparently make things more efficient, as they eventually would have). Oh, and the fact that you can't use the floating point processor directly to calculate transcendental functions (it's done in software instead). …
When I wrote about how badly generics were designed, I got the same response, along with "we must be backwards compatible with previous (bad) decisions made in Java." Lately more and more people have gained enough experience with Generics to see that they really are very hard to use
Bill Venners remembers things differently:
I'm not sure where you got the impression that the choice of leaving out operator overloading was because someone didn't do their homework. I remember asking this Gosling in one of my interviews of him why he left out operator overloading (I don't think that question and answer ended up getting published). What he basically said to me, is what I heard him say in other contexts: Gosling felt that the level of operator overloading abuse he had seen in practice in other languages (I'm not sure if this was just C++, but certainly included C++) had outweighed the benefits of it. That's all. It was a subjective design choice.
James Watson favors the limitations purposely introduced in Java:
What has made Java a good fit for these shops is that it is easy to follow Java code. Yeah, you can write unmaintainable code in any language but you have to work at it in Java. It doesn't provide a lot of the features that are so easy to abuse in other languages.
From an individual's perspective, this is terrible. If I don't want to use a feature I won't use it. Who is Sun to tell me what I should do and shouldn't do? But when you take a group of developers who have different ideas about what a good approach is, the game changes. Having a limited number of ways to do things starts making sense.
Noel Grandin added his bit, broadening the debate even more by including new languages:
Most of the other "hot" languages like Ruby, Scala are never going to hit mainstream, because they're all biased to heavily in favor of writing code, instead of reading code.
Java got this balance correct - Java might be verbose and lack lots of "cool" features, but it's really easy to figure out what some random code is doing.
In the end, Eckel talked about Java’s legacy:
Java brought the mainstream of programmers into the world of garbage collection, virtual machines and a consistent error handling model (especially if you subtract checked exceptions, which is possible using techniques I show in Thinking in Java, 4e). With all its flaws, it moved us up a level, to the point where we are now ready for higher-level languages.
The most positive factor is preparing the way for future languages:
At one point, C++ was the leading language and people thought it would always be so. Many think the same about Java, but Java has made it even easier to replace itself, because of the JVM. It's now possible for someone to create a new language and have it run as efficiently as Java. …
And we are seeing this happen -- both with higher-level static languages like Scala, and with dynamic languages, both new and ports, like Groovy, JRuby and Jython. …
The unintentional benefit, the true accidental brilliance of Java is that it has created a very smooth path for its own replacements, even if Java itself has reached the point where it can no longer evolve. All future languages should learn from this: either create a culture where you can be refactored (as Python and Ruby have done) or allow competitive species to thrive.
Java ignited many disputes when it appeared, especially between C++ and newly formed Java developers. Voices have calmed down since then, and we can see clearer now where we stand and what is the legacy left by both languages. Or maybe is it too early to talk about their legacy? It sounds a bit like they are dead or dying languages. (Opinions are welcome as always.)
Community comments
Legacy != Dead
by Bill Karwin,
Java is easier to read?
by Ryan Riley,
Possiblity adds complexity
by Oziel Jose,
Re: Possiblity adds complexity
by Dmitry Tsygankov,
Re: IBM buyout of Sun
by Luis Espinal,
Legacy != Dead
by Bill Karwin,
Your message is awaiting moderation. Thank you for participating in the discussion.
C++ and Java are still alive and used widely. O'Reilly market report shows Java is in 2nd place (211k books sold in 2008), and C/C++ is in 5th place (145k books sold).
However, we can look at them with some perspective, now that other languages have also become popular, and many are clearly responses to the lessons learned from C++ and Java (C#, PHP, JavaScript round out the top five according to O'Reilly).
So it's okay to make observations about the contributions C++ and Java have made to programming language evolution.
Java is easier to read?
by Ryan Riley,
Your message is awaiting moderation. Thank you for participating in the discussion.
I find Mr. Grandin's comment the most interesting of all of the comments listed. I code a lot of C#, not Java, but overall I would have to disagree and say that Ruby and Python are much easier to read. Some of the explicitness of statically-typed languages is missing, but generally I can read the intent much easier.
I find this true of many functional languages, also. The verbosity is reduced, along with explicit type labels (due to excellent type inferencing) and thus the readability is greatly improved.
Possiblity adds complexity
by Oziel Jose,
Your message is awaiting moderation. Thank you for participating in the discussion.
I think that when everyone mention java as legacy or as a dead language, and mentions design decisions i find very amusing.
When i look at the code cobol produces i think that java is the one complicated, and i have never worked with cobol, when i try to use events and delegates in c# it made my code look more complicated, and if i need to be used to it to undestand, it means thats not very easy so in the end it adds compexity...
So cool words dont mean that the code will be cleaner, it actually means that you will have more trouble to understand it...
Re: Possiblity adds complexity
by Dmitry Tsygankov,
Your message is awaiting moderation. Thank you for participating in the discussion.
Sometimes - yes, when possibilities are added on top of the existing structure. Sometimes not, when possibilities are wired into the language from the beginning. Can anybody tell me, for example, why is that 'this' parameter so special in Java/C#/mainstream languages? It doesn't seem to make sense, a method can do things with many objects at once and it's not always obvious as to where we shall put it. The existing alternatives of polymorphic systems without that magical 'this' are the Common Lisp CLOS system or the type class system of Haskell. They seem to add possibilites, but are they more difficult to understand? I doubt it.
There is one more thing here - complexity can be of two kinds. The complexity of the language itself and the complexity of programs written in that language. When I read a complex program, I have to be sure of certain things, like the value of some variable, or that when I call a function twice, it will produce the same result, or that the method I'm trying to call doesn't write to the database, or that the certain method can only be called by me, not by a user of my library. And it seems to me that dynamic languages like Ruby, Common Lisp, etc., while removing some of the complexity of the first kind, add to the complexity of the second kind - one cannot reason about the programs written in Ruby that easily. Java and C# with generics seem to do a better job here, but Haskell seems to be even more precise when it comes to the contracts of methods.
Re: IBM buyout of Sun
by Luis Espinal,
Your message is awaiting moderation. Thank you for participating in the discussion.
That's because it was irrelevant to the conversation (which was about the HISTORICAL good and the bad of Java and C++, not on hypothetical cases.)
As for Watson/Grandin's about Java code lending itself to be easier to read. I would like to invite them and see some of the Java code that I've had the displeasure to work with.
You might have omitted multiple inheritance and operator overloading from Java and what not, but the verbosity of the language makes it horrendous to read, specially at the hands of inexperienced (read "bad") programmers.
There are different types of "ugly". C++ might have it's type, but verbose Java has its type as well. Different types, but equally horrid and putrid. Saying that it lends itself to be easier to read is living in fantasy land.