Java Three

Elliotte Rusty Harold wrote an interesting if overly-cautious article over at OnJava? listing "10 Reasons We Need Java 3.0" (http://www.onjava.com/pub/a/onjava/2002/07/31/java3.html). The idea is that there should be a new version of the JavaPlatform which explicitly breaks backwards compatibility in order to make the JavaLanguage (the platform and all the related APIs like J2EE) a more suitable language for the 21st century. This means discarding features that only made sense back in the early '90s when this was a language for toasters and adding features that make sense for the uses that Java is being put to today.

It would be helpful if people could indicate why their proposed changes would be beneficial.


So what features should go into JavaThree given that backwards compatibility isn't an issue but conceptual integrity matters?

// Connect a callback to a GUI button
button.onPress() { ActionEvent event |
System.err.println( "button " + button_index + " pressed" );
}

// Find an element in a list list.forEach() { Object element | if( isTheElementWeWant(element) ) { return element; } }

// or even shorten that to: list.find() { Object e | isTheElementWeWant(e) };

// In the NiceLanguage (extension of Java with closures, generics, ...) you can write: list.find(String s => s.startsWith("abc"));
The drawback with this is that the syntax doesn't match the built-in control structures. Like "for" you mean? Built-in control structures are more low-level and verbose than methods taking an anonymous function. In most cases you can replace a several-lines-long "for" by a one-liner using foreach, map, find... Therefore it is not clear that their syntaxes should match. True, it would be possible to have an ad hoc syntax like "foreach (String s in c) {...} ", but that does not extend to other uses of anonymous functions like callbacks, so this would go against the principle of minimality. JavaLanguage does not have closures, so you need to invent some syntax, but then you get many powerful uses. AnonymousInnerClasses are closures (just not very good ones, and with extremely verbose syntax, which was the reason that this thread kicked off in the first place). (See also BlocksInJava)

// or, if isTheElementWeWant is a function taking an element returning a boolean:
list.find(isTheElementWeWant);
And further, reintroduce the LispLanguage-style "FixNums?", 30-bit integers that can be safely pushed into pointers without boxing. SunMicrosystems Sparcs actually have hardware support for such integers. (and 30-bit floats while your at it.)

The cost of this in DotNet is minor (I checked). The compiler can optimize out many checks using the same techniques as optimizing out array bounds checking. CeeLanguage/CeePlusPlus are the only vaguely modern languages not to provide overflow checking...


What benefit does the block syntax give over the current approach in the JavaLanguage? Conceptual integrity is important and the above syntax overloads the pipe (|) symbol in a way that might help the smalltalker but will needlessly confuse Java programmers. Why do we even need blocks? It looks like a solution in search of a problem. The two examples are easily written in idiomatic Java.

Well, certainly the second block example is excessively verbose in idiomatic Java. You have do to something like:

Object result = null;
Iterator i = list.iterator();
while(i.hasNext()) {
Object o = i.next();
if(isTheElementWeWant(o)) result = o;
}
That's a whole lot of lines of code for something that's really quite simple. If Java did have InternalIterators, this could compress to:

list.find(new Predicate() {
public boolean isTrue(Object o) {
return isTheElementWeWant(o);
}
});
Maybe the InnerClass and its method can be named better or something, but this is still pretty hard to read. -- ChristianTaubman

Exactly! The InnerClass syntax is extremely verbose for something that is essentially a user-defined control structure. User-defined control structures should be as readable as built-in control structures. A good syntax for user-defined control structures is extremely important, and it's a real shame that the JavaLanguage designers dropped the ball when they added AnonymousInnerClasses. A clean way of defining blocks would have also resulted in a simpler and more flexible event model in the JavaAwt and JavaBeans.

"Conceptual integrity is important and the above syntax overloads the pipe (|) symbol in a way that might help the smalltalker but will needlessly confuse Java programmers."

I agree. The pipe symbol is not the best syntax to use. Perhaps a colon would be better:

button.onPress() { ActionEvent ev :
System.out.println("pressed");
}

// remove items that match a predicate list.filter() { int element : return element >= 0; }

// create a list by applying a function to elements of another list List<int> squares = list.map() { int element : return element * element; }

// multiple arguments to the block map.each() { Object key, Object value : System.out.println( key + " => " + value ); }
(See also BlocksInJava)


The important thing, I think, is that by adding a very small number of features, or even just by reorganizing things a little, we can remove a whole lot of other features. If classes are objects, the whole idea of "static" can go away. Constructors can go away, too - they can just be methods on the class object. Wonderful, we can get rid of the chapter in the JavaLanguageSpecification about statics, and the one about constructors too. Save trees.

If we have blocks, we don't need "if" or "while" or "for". We don't need the next()/hasNext() Iterator dance, or any of the more complex patterns that are built on top of it. We don't need the "synchronized" keyword - it can just be an ordinary method that takes a block as a parameter. We don't need to remember to call close() on our files or other resources.

The people who are asking for these features aren't trying to make the language more complex - they're trying to simplify it. The ideas sound weird because JavaLanguage programmers aren't used to them, but they're things that'll let us express more of our concepts directly in the language. We won't need to remember that "find something in this collection matching this criterion" means "make an Iterator object, loop while iterator.hasNext(), call next() on the iterator to get an object, check the object against our criterion, break out of the loop if it matches". We'll just write the Collection.find(criterion) method, it'll be part of the standard library, and millions of Java programmers will be able to reclaim that space in their memory.

I've got some other problems with JavaLanguage, but they're more fundamental. When people say, "We need Java 3.0," I think, "No, we need SmalltalkLanguage, and we've already got it." And we had it 20 years ago. Sigh. But if the question is, "How can we improve Java while still keeping its underlying philosophy?" then I think that there are lots of things that we could do to make the language simpler and more powerful without losing Java's spirit.

-- AdamSpitz

Very well put!

What about macros, Adam? You forgot to include macros! ;-) -- NoelWelsh, trying to stir up trouble.

I was leaving that for you. ;) If you think you can make Java programmers understand macros, be my guest... -- as

Ok, so JavaLanguage programmers can reclaim that space in their memory. Won't that require them learning something else until their memory is nearly full, to increase the GarbageCollection pressure enough to prompt a collection? Maybe they should learn CeeSharp. That way, they'll be able to pass memories to their kids! (Note to reader: The CommandLineInterface has a generational GarbageCollector.) -- DominicCooney


With regard to "we need Smalltalk" I'm afraid that the world and his dog have rejected SmalltalkLanguage. For some reason they/we don't want Smalltalk. That leaves us with two choices. Either persuade the world that it really wants Smalltalk. Something which smacks of the marxist idea of false consciousness. The alternative is to ask WhyIsSmalltalkDead and learn from that.

With regard to "we don't need if while or for". That's true. If you have 1s and 0s everything else is just SyntacticSugar. Unfortunately making different things look different rather than similar makes languages easier to learn and use. Shoving blocks and other functional features into JavaLanguage just won't fly. Java isn't a FunctionalProgrammingLanguage, and I don't believe that there's even a migration path that would allow the language to become ObjectFunctional without turning it into something completely different.

Different languages are different because they fulfill some need that exists out there. JavaLanguage exists as a simplified, cleaned-up CeePlusPlus which emphasizes impure OO programming and the kind of deep linguistic conservatism necessary to persuade the mainstream, with its hordes of ill-educated over-worked coders, to adopt it. RichardGabriel's PatternsOfSoftware explains all of this in much more detail and describes why 'sophisticated' languages don't succeed in the mainstream. Sad but true.

-- AnonymousDonor

It's certainly true that SmalltalkLanguage isn't popular, but that doesn't mean that the world has learned its lessons. I think that the Java culture has a few good values - simplicity, readability - but the JavaLanguage is an atrociously bad implementation of those values.

Some Java programmers - the "deeply conservative" ones - won't care; they'll reject anything that looks weird. But some Java programmers are just people who recognize that Java has a lot of advantages over whatever they're used to, and don't realize that there's anything better out there. These people aren't likely to try Smalltalk - because, of course, it's "dead" - but if we can improve Java in ways that are consistent with the culture's values, they'll learn and benefit.

-- AdamSpitz

"If you have 1s and 0s everything else is just SyntacticSugar."

True, but the SyntacticSugar is important. That's why people program in HighLevelLanguages, instead of entering programs with toggle switches on the cabinet. Adding blocks to the language would not be a huge step. JavaLanguage already has a form of closures in AnonymousInnerClasses. Unfortunately, the syntax for anonymous inner classes is incredibly verbose for most of the things they are used for. The advantage of good syntax for blocks would not be to replace the built-in control structures, but to allow programmers to augment them in as seamless a way as possible. See PythonVsRuby for some examples of how blocks can be used to augment a language's control structures.


What About AspectJay? I'd like to see it integrated into JavaThree.


OperatorOverloading. Please throw a bone to those of us who want to be able to have the same capabilities in our objects that the JavaLanguage designers have with String.

Complex a = { 1, 2 };
Complex b = { 1.4, 2.45 };
Complex c = { 500, 2.3 };
Complex d = ( a + b ) * c;  // Pretty unambiguous, eh?
Rather than:
Complex a = new Complex( 1, 2 );
Complex b = new Complex( 1.4, 2.45 );
Complex c = new Complex( 500, 2.3 );
Complex d = a.add( b ).multiply( c ); // or did I get the order wrong?
-- GeoffSobering

OperatorOverloading was rejected for very sound reasons by the original design team. I don't see it creeping back in. And, as someone who once saw the <= operator used to indicate putting stuff into a SmartPointer, I'm very glad of that. -- RobertWatkins.

Just FYI, JamesGosling has somewhat relaxed his original attitude towards OperatorOverloading: http://java.sun.com/people/jag/FP.html#overloading (BrokenLink) -- GeoffSobering

I once saw someone create a method with a really bad name. How come we let people write their own methods, anyway? Why isn't it good enough for us to just use the methods provided by the Java designers? ;)

The difference is that naming methods is better, in just about case, than having lots of anonymous methods floating around. Whereas OperatorOverloading has lots of negative aspects and the only positive uses are complex numbers and being able to treat collections like arrays. Given that JavaLanguage's evolution is mostly being driven by the J2EE market then operator overloading is never going to go in as the vast majority of Java developers won't benefit from it. Languages aren't like MicrosoftWord or EmacsEditor where everyone can have their pet feature/extension added without adversely affecting others too much. With languages your penchant for operator overloading is my headache. I can't learn just a subset of the language because I have to work with other people who may have learned a different subset. Because features can't be optional then the only features that should go into a well designed language are features that contribute to the whole. Where whole means the whole language as a complete construct and the whole community of developers who have either learned, are learning or actively using that language. -- AnonymousDonor

It seems to me that there are two different questions to be asked here:

  1. Are we afraid that programmers are going to misuse this feature?
  2. Is the value of the feature higher than the cost of the extra complexity?

This is where the cultural issues start to come in. In the languages I like, the answer to question #1 is always "No." I trust myself, and I trust the people I work with. I suppose that some people don't have that luxury (though I don't know how they manage to get any work done).

I still value simplicity, so I'm drawn to languages like SmalltalkLanguage and LispLanguage, which are very simple and very permissive (as opposed to languages like CeePlusPlus and PerlLanguage, which are very complex and very permissive).

JavaLanguage, though, seems weird to me, because the language doesn't seem to match the culture. Java people seem to value restrictiveness and simplicity, so I would have expected Java to be a simple but restrictive language - but instead, it turned out to be a complex and restrictive language. So when I started wondering what Java 3.0 should be, I thought, "Still restrictive, but get rid of all the complex historical gook." (See also BondageAndDisciplineLanguage)

-- AdamSpitz

The thing about JavaLanguage teams is that most of them tend to be doing in-house development for large conservative organizations. As such the teams have a wide range of people in them with different levels of skill with Java, programming and OO. Therefore the language is simple in the sense that no feature should be so exotic that people haven't seen it before (the language is meant to consolidate existing ideas in CS not invent new ones) or need to go through yet another paradigm shift. But it's restrictive in a bid to protect the team from its weakest members.

Look at http://java.sun.com/people/jag/OriginalJavaWhitepaper.pdf for a paper that points out that JavaLanguage is meant to only be simpler and more restrictive than CeeLanguage/CeePlusPlus not as an absolute goal. Look at this page http://java.sun.com/docs/white/langenv/Perform.doc2.html#1834 for a comparison of Java against various languages including SmalltalkLanguage by Java's designers. Java makes much more sense once you've read the whole document at http://java.sun.com/docs/white/langenv/. Also this interview with JamesGosling at http://www.javaworld.com/javaone99/j1-99-gosling_p.html is extremely insightful especially the section at the end on "Java language development in the enterprise" as it shows what kind of world the designers are designing for. And of course http://www.artima.com/intv/gosling3P.html


"No feature should be so exotic that people haven't seen it before."

I give up. I don't know how to design a good language for people who aren't willing to learn new things. -- AdamSpitz

Maybe that's the essential problem with JavaLanguage. It got popular before it got good. And now it's too popular to fix. Perhaps that's why all the interesting work on evolving Java is being done independently through projects like AspectJay, GenericJay?, JOOS (see the LambdaTheUltimate weblog for more info) and NiceLanguage? Getting mainstream Java fixed meets too many entrenched forces so the syntax is being forked.


Make classes be real objects. If I have a class named Car, then "Car" should be a reference to the class object (which can be passed around like any other object), and "Car.numberOfWheels()" should be a call to an ordinary method on the class object. So if Car is a subclass of Vehicle, and v is a variable of type Vehicle, I want to be able to write "v.getClass().numberOfWheels()".

I might be confused but we already have this through Car.class? -- Anonymous

Okay, so classes are objects; what class are they? In order for your example to work, it has to be a class declaring numberOfWheels() as an instance method; think about that for a bit and you'll see where the problem is. I'm sorry, but what you want is impossible in a StronglyTyped system. The best you're going to get is some language-level support for polymorphic invocation of static methods, which will involve a 'class' type which behaves very differently to object types, in that dispatch is fully dynamic, and each instance supports a different set of methods.

I don't like the word "impossible", but if you'd said, "StaticTyping makes this feature too complex to be worth implementing," I might agree with you. What does this teach you about the tradeoffs involved with introducing static typing into a system? -- AdamSpitz

The idea is, each "class" actually generates two classes: the class for its instances, and the MetaClass - the class of the class, as it were. This may sound extreme, but think about it for a few seconds and it makes sense. And no, it doesn't behave very differently than existing object types. In fact, it's almost indistinguishable.

Several languages already use MetaClasses, and they do work. -- MarcusDowning?


See also JamesStrachan's list of suggestions: http://radio.weblogs.com/0112098/stories/2002/11/12/j.html

Count me in :) http://www.dehora.net/JavaFixme.html (BrokenLink 2004-12-27) -- BillDehora


Increase the power of JavaInterfaces by adding DesignByContract. EiffelLanguage is a good example how this can be achieved. Also, Barter (http://barter.sf.net/). -- TobiasRademacher?


"and the only positive uses [of operator overloading] are complex numbers and being able to treat collections like arrays".

Anyone who can say that has never worked on a business system. And business systems are Java's main application area.

Give us some specific examples where operator overloading is crucial to working with business objects. Ignore the obvious, trivial examples like dates and money.


See also: JavaDesignFlaws


CategoryJava


EditText of this page (last edited March 10, 2006) or FindPage with title or text search