JavaNG: A Better Java – What would you do?
Forget the shackles of backwards-compatibility. If you could make changes to Java to make it a better language, what would you do? I don’t mean drastic surgery so that you end up with Lisp on the JVM, but what could be done to make Java a better platform-independent, object-oriented language?
Bruce Eckel has some interesting thoughts about the evolution of Java and Sun’s commitment to backwards-compatibility. I have to agree that backwards compatibility will eventually kill Java if new features are continuously compromised by nasty hacks (e.g. erasure) to avoid breaking legacy code. At some point, the guardians of Java must choose new features or backwards-compatibility. To continue to demand both is not sustainable.
With this in mind, I’ve made a list of things that I personally would like to improve in Java, assuming that backwards-compatibility is not a primary concern. I’m interested to hear others’ suggestions, so leave a comment at the end if you have better ideas.
If it weren’t for Sun’s marketing department, we could have called it Java 2. Java++ is just wrong, so I’ll follow Cedric’s naming scheme and call it JavaNG – the next generation OO language for the JVM.
Maybe it’s just me, but this really bugs me…
Firstly, and it may seem trivial to most, but I would scratch an itch that has been bothering me for over a decade. The Cloneable interface does not define the clone method. An object must define a public clone method in order to be cloneable, but the Cloneable interface does not require this. Therefore it is perfectly legal to implement Cloneable yet not be cloneable. Of course, any class that does this is obviously broken, yet the Cloneable interface apparently cannot be changed since such a class would no longer compile. In my opinion, Sun would be doing developers a favour by making the compiler complain about this. FFS Sun, you broke everybody’s code by adding the assert keyword in 1.4, why would fixing Cloneable be such a big deal?
Is this an object-oriented language or not?
Right, now on to more substantial concerns. Primitives have to go. Everything should be an object. It would simplify learning the language and primitives don’t mix with generics without auto-boxing (and auto-boxing is horrific). No primitives – no auto-boxing – no problem.
I believe that primitives were originally included in the language because of performance concerns about doing everything with objects. Well virtual machines and hardware have both moved on significantly since the mid-90s. And if Ruby seriously is the main competition, then performance clearly doesn’t matter anyway.
BigDecimal.ONE.add(BigDecimal.ONE).compareTo(new BigDecimal(“2″)) == 0
Obviously if there are no primitives to unbox to, then the arithmetic operators have to be defined to work on the appropriate object types (java.lang.Integer, java.lang.Double, etc.). But why stop there? Arithmetic operators for BigInteger and BigDecimal are long overdue. Without first-class support for arbitrary-precision arithmetic, Java is not a sensible choice for many types of application. I mean, how hard should it be to assert that 1 + 1 = 2?
Types are for life, not just for compilation
I want generics without erasure. Since I can accept breaking backwards compatibility where necessary, I don’t have to accept a weaselly implementation compromise and the resulting frustrations of not being able to inspect type information at runtime.
Just say no to null
For a language that supposedly doesn’t have pointers, there are an awful lot of NullPointerExceptions in Java programs. The simple truth is that developers have proven to be incapable of keeping track of which references are allowed to be null. I want the language to do this for me. More specifically, I want the type system to do this for me. The Nice programming language has the concept of option types. I want one of those. If my method declares that its parameter cannot be null, then any attempt to pass it null (or even to pass it a value of a nullable type) should result in a compiler error. Non-nullable types will become the new ‘final fields’. They’ll be used everywhere unless there is a good reason not to.
Literal bias
Java’s verbose they say. Well Java will always look a bit wordy when compared to Python with its sleek dictionary syntax. But we could have that too. Literals for maps and lists would help to make code more concise and more readable.
Tuples
According to Gilad Bracha, Java was supposed to have had tuples from the start, they just never made it into the language. It’s time to rectify that. No more writing several trivial little classes (or generic Pair and Triple classes) just to wrap together multiple return values.
The stuff that didn’t make it…
I think that list is long enough for now (though I’m sure I’ll think of more later). You’ll notice that I haven’t taken a position on closures. I’m unconvinced and undecided. I need to read the proposals properly. In the past I’ve advocated first-class functions for Java, but for now I’m deferring on that too, at least until I’ve picked a side in the closures debate. I also think that the original Java designers got it right when they left multiple inheritance and operator-overloading in C++ land.
If you think you have a better plan for JavaNG, please add a comment. I’ll post a follow-up in a few days summarising the suggestions.

on January 4th, 2008 at 6:22 am
I agree with many though not all of your opinions. Note that this differs from Scala in several points, however. (Examples: complicated generics, no null handling, C#-ish value types rather than pure OO.) Part of why I think Scala isn’t the best idea from JavaNG. But I guess we all have different opinions on things. And yes I do like closures (and anonymous functions for those that care so badly about the difference – even though anonymous functions are the main use for closures for languages that make them work well).
on January 4th, 2008 at 6:48 am
I agree with everything you are saying. Closure would be lovely though, vastly reducing LOC in ui driven interfaces.
The thing I would love is to remove most, if not ALL final classes in the JDK. E.g. final class Integer. I want to be able to define a class:
public class Int extends Integer{
public Iterable to(Integer limit);
}
Then we can have niceties such as:
for( Int i : zero.to(ten) ){
}
It really bugs me that classes such as Date are final. Its horrid and really reduces the ability to create nice fluent API’s.
Another one I could see being useful quite a lot, and I am not sure if ANY language has it could be turning code such as:
object.doSomethingTo(object.anotherthing().and(object.somethingElse()));
into:
using: object {
doSomethingTo(anotherThing().and(somethingElse()))
}
Kind of like making the object’s methods inlined within the block I guess. Random ideas!
on January 4th, 2008 at 9:22 am
1.) Properties. This reduces noise by removing simple setter and getters
2.) Nice option types. The biggest problem currently left in Java are NPEs. Most other problems have been delt with compared to C++
3.) Better class cast exception descriptions. WHAT was tried to cast to WHAT? The current description is plain unusable (And WHERE was the object with the wrong type created?) Also see next, structural typing.
4.) Structural typing. This would make reuse much easier.
interface Foo {
public void doFoo();
}
Currently Java (contrary to Scala) only has declarative typing. So I only can call
public void myFoo(Foo foo)
with an object that DECLARES to implement foo. Java should look at my object if it does “implement” Foo by structural comparison, not because someone declared it to implement Foo. The Scala way of saying
public void myFoo(T foo)
is more powerfull, but less readable. I would prefer the interface way.
Peace
-stephan
on January 4th, 2008 at 1:40 pm
Wordpress comments thought my type annotations where HTML and removed them.
public void myFoo(T[public void doFoo()] foo)
to express that myFoo works with any type that has a doFoo method.
on January 4th, 2008 at 6:49 pm
Stephan, am I right in thinking that your “structual typing” is analogous to “duck typing” in Ruby?
I think that’s a pretty fundamental change to the type system and would require a new way of thinking when developing. It would however make my point about Cloneable irrelevant – we wouldn’t need a Cloneable interface, so I can see the attraction for simple interfaces.
However, I don’t see having to declare “implements MyInterface” as being a problem in Java.
The argument I’ve seen made against duck typing is the (extremely contrived) example of the ZipFile and the AtomicBomb types that both have an explode() method. Use the wrong object and you’ll get a rather different result that the one you expect.
I’m definitely with you on point 3 (ClassCastExceptions). There are no backwards-compatibility excuses for not doing this right now.
on January 9th, 2008 at 12:24 pm
“Stephan, am I right in thinking that your “structual typing†is analogous to ‘duck typing’ in Ruby?”
No structural typing is static and type safe. Duck typing is currently associated with dynamic typing. I guess some people would call “structural typing” chicken typing. But only because they have never been biten by a nasty type bug which had costed them k’s of USD.
“However, I don’t see having to declare “implements MyInterface†as being a problem in Java.”
a.) It creates a _broad_ dependency. Often too broad.
b.) What if you do not control the code to declare the dependency?
Peace
-stephan
on January 11th, 2008 at 5:13 am
[...] but it’s a mature language, so it will evolve slowly. I’ll also throw out a link to Dan’s post on Java NG as a fun place to throw out ideas on what you could do with all constraints [...]
on January 11th, 2008 at 3:14 pm
JavaNG sounds like a tropical island with blue lagoons, palm trees and bikinis ladies with… agh snap out of it, back to the cold city with it’s graffiti covered concrete and rat infested sewages.
I would add properties and events (delegates), fix the lousy component model, make sure versioning is build in (i.e. non-virtual methods by default etc.) and drop pluggable L&F (people on a mac want the mac stuff and so forth). Operator overloading is long needed to fix a bunch of horrific API’s, nullable types would be nice, but for god sake get rid of the primitive types and add inference (would also fix the tuple issue). Oh god I want to go to that island so bad!
on January 11th, 2008 at 8:04 pm
Good post – a couple of things I have suggested:
1. Add a source keyword so that you can mark a file as Java 7, then you don’t need to worry so much about backward compatibility and you can fix up the errors from the past (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519124)
2. You can write a good tuple library already using generics:
T2 swap(E0 e0, E1 e1) { return t(e1, e0); }
Note generics and ease of construction.
You can see the code and more examples at:
http://code.google.com/p/google-collections/issues/detail?id=43
on January 11th, 2008 at 8:25 pm
Oops the generics didn’t come out, below I have used [] instead of angle brackets for the code
[E0, E1] T2[E0, E1] swap(E0 e0, E1 e1) { return t(e1, e0); }
If you had native tuples the above might look like
[E0, E1] (E0, E1) swap(E0 e0, E1 e1) { return (e1, e0); }
As you can see; not very different. The main difference would be access to the tuple members via .e0 etc., e.g.:
T2[Integer, Integer] maxMin = t( 0, 1 );
maxMin = swap(maxMin.e0, minMax.e1);
As opposed to:
(Integer max, Integer min) = ( 0, 1 );
(max, min) = swap(min, max);
On the other hand you can do:
class MyClass extends T2[Integer, Integer] { … }
with the library; most languages that have tuples don’t allow you to extend the tuple class.
on January 13th, 2008 at 9:25 pm
1) Have an (optional) character-encoding on the first line. Useful for both compilers and IDEs.
2) Introduce an Id type, similar to String but also to Long. Great for equality testing, lookup though String value possible.
3) Remove equals and hashCode from Object. It is only used in HashMaps and HashSets and if is currently too difficult to get it right. Introduce a new interface to contain these methods.
on February 21st, 2008 at 10:41 pm
An object can define a protected clone method if it wishes to restrict access. If the Cloneable interface had specified the clone method this would not be possible. Whether anyone actually does this is another question.
I understand that, even with the best compiler technology, eliminating primitives still has a noticeable performance cost for some types of computation.