views:

169

answers:

3

Since this question is back to four votes to close, I'm trying again to ask a more narrow question that hopefully the community will view more favorably.

Which specific design decisions in Java are documented to be done the way that they are not because that was the preferred design decision, but rather because it was necessary to support backwards compatibility.

The obvious case is Generics, where you cannot detect the type parameter at runtime. (So you can't do:

 public void addEmptyMember(List<?> someList) {
      if (someList instanceof List<String>) {
            ((List<String>) someList).add("");
      }
 }

What other such examples exist in the language design and standard API?

+2  A: 

Because this question doesn't have a single right answer, I'm not sure if it'll fare any better than your other question.

Three features I can think of (in addition to generic erasure, which you already mentioned) that made compromises in the name of backward compatibility were the new for loop syntax, varargs, and autoboxing.

The new for loop syntax probably should have read for (item in List), but that would have required making in into a reserved word. This would caused numerous backwards compatibility problems, not the least of which being the fact that System.in would have to be renamed.

varargs and autoboxing both added the possibilities of ambiguity. For example, if you pass an array of Objects to a method that accepts Object... does that mean the array should be passed as the vararg array or as an element of the vararg array? This gets even more complicated if there are overloads. Autoboxing has similar ambiguity problems with overloading. The solution to both of these problems was to make it a rule that when resolving method calls they are first resolved with the pre-1.5 rules (ie: no autoboxing, and Object... is treated as Object[]). Only if the method call can't be resolved with the pre-1.5 rules are the new 1.5 rules considered.

Laurence Gonsalves
Is the third one really choosen for backward compatibility as the only/main reason? It seems to me it makes sense even without backward compatibility in mind.
Jens Schauder
In any implementation of varargs that was in the language from the beginning you'd want there to be a separate syntax for "explode this array and pass its elements as the arguments in the varargs". (For example, the *args calling notation in python, or even the apply function in lisp) They didn't want to do this in Java, however, because they wanted to be able to "upgrade" existing API functions to use varargs while having all of the old callers (that expected an array) to still work.
Laurence Gonsalves
+2  A: 

Another one would be all the classes and methods that are deprecated for multiple versions by now, but just won't go away. Most notable are the various Thread methods, that are deprecated.

Jens Schauder
Certainly true. I remember when they made System.getenv() throw an exception instead of returning a result - but they left the method in there for backwards compatability!
Yishai
+3  A: 

There are lots of examples in the standard library

  • java.awt.Color has the same constants with upper and lower case names
  • All the deprecated methods in java.util.Date given the introduction of java.util.Calendar - what a mess!!
  • java.util.Enumeration still being used where java.util.Iterator could replace it
  • Classes in Swing that accept Vectors as arguments but could have had support added for java.util.Collection
Mark