The Artima Developer Community
Sponsored Link

Weblogs Forum
Java: Evolutionary Dead End

92 replies on 7 pages. Most recent reply: Jan 3, 2008 9:06 AM by Bruce Eckel

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 92 replies on 7 pages [ 1 2 3 4 5 6 ... 7  | » ]
Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Java: Evolutionary Dead End (View in Weblogs)
Posted: Jan 3, 2008 9:06 AM
Reply to this message Reply
Summary
This sounds bad, but it needs to happen if Java is to ultimately stay in the mainstream. That is, if feature accretion hasn't already irreparably damaged the language.
Advertisement

I'm at Javapolis in Antwerp, Belgium, where I've given a keynote. It's Friday morning, and the day before, Josh Bloch gave a presentation comparing the issues in closures proposals. He sits across from me at breakfast and we further discuss the topic.

Since the beginning I've complained that, at the same time that it claims to be simple, Java is too noisy as a language. Code is read much more than it is written, and this noise directly translates to real costs in software development. Brain cycles are a very scarce resource, and anything that uses them up without benefit -- even something as seemingly innocuous as the extra verbiage in System.out.println() -- takes those cycles away from somewhere they could be useful, and reduces the programming efficiency of the language (Steve Yegge recently wrote about this problem).

In his presentation, Josh said that the last-minute addition of wildcards to Java generics may have pushed the complexity of the language too far. Neal Gafter has suggested that we reify generics. Both were originally unequivocal fans of Java generics, based on their responses to the criticisms I wrote about the topic. Now there seems to be a shift, and I've also seen other people begin to say "generics are still great but..." (Although Tim Bray recently called them a disaster).

The only control we have over complexity is abstraction: hide the parts that don't matter ("divide and conquer" is a variation). The paradox of Java is that a critical aspect of the complexity problem was ignored; code readability was not considered an important issue. It seems that if the IDE writes the code for you, then it doesn't matter if that code is needlessly complex.

Josh took this idea of complexity one step further. He said that it's not just the complexity of a particular feature in isolation, where it can often seem fairly straightforward. It's the combinatorial complexity that you get when you combine a new feature in every possible way with the other language features. When you shoehorn a feature into an existing language rather than carefully designing it in from the beginning, you cannot control how that feature combines with other existing features. The combinatorial complexity can produce horrifying surprises, typically after the feature is added when it's too late to do anything about it. Over breakfast Josh noted that this kind of complexity makes for a bountiful supply of Java puzzlers; entertaining for him but not good for the community as a whole.

Stability vs. the Feature Junkies

My epiphany from the impromptu breakfast with Josh was that I am a feature junkie. Features are fun puzzles that, once you figure them out, can be used in fascinating ways. So I've always thought of language evolution in terms of new features. You may discover that you're a feature junkie too.

So when features like Java Generics are added badly (in my opinion) to the language, I find it frustrating and my perspective is that they should have just done the right thing when adding the feature.

But it never really occurred to me that maybe the right thing to do is just not add the feature at all (what fun is that?). That if you can't do it right then maybe the language should stop growing and become stable. That it should stop chasing every language feature du jour.

Arguably one of the best features of C is that it hasn't changed at all for decades. C++ has also been very stable. In that context it doesn't sound so bad that Java stabilize.

This isn't to say that features like generics and closures are "bad." Not at all. When well-designed into a language, they can be clear and powerful. But Java had that chance, back at the beginning: Bill Joy made a strong argument to include things like closures and generics before the initial release of the language, but was ignored.

People lived tolerably for many years, then suddenly it became essential that generics be shoehorned into the language. This was remarkably coincidental with the appearance of generics in C#, which also appeared to produce several other features in Java 5. It seems that the urgency of these features came not from solving true problems in the Java language, but in Sun trying to maintain the perception of competitiveness against Microsoft's C#. This is probably not so far off the mark, because the reason that Java had to be rushed out in rough form in the first place was the belief that there was a market window that must be captured. A programming language designed by following marketing impulses is eventually going to end up chasing its tail.

The Compatibility Grail

One choice would have been to insert the feature correctly and to break backwards compatibility. As a feature junkie that would be my choice because it wouldn't degrade the integrity of the language. This approach was consistently denied because backwards compatibility has always been one of the war axes of the language. I observe that Python has broken backwards compatibility in a small way in an earlier version, amidst much trepidation. The change happened with virtually no backlash, and as a result Python 3 is planning more significant backwards incompatibilities. Ruby is planning on removing many of its Perlish features in order to clean up the language. People who don't want to deal with these changes don't upgrade, and those people tend not to upgrade anyway, out of conservatism. Many companies are still using Java 1.1 for that reason. Those people are not going to be affected one way or another by this debate; they don't plan on changing in any case.

If we can't insert features correctly because of backward incompatibility, we are straightjacketed when it comes to language changes; we are in the same position as C++. C++ is often criticized because of its design, but I was on the standards committee for 8 years starting at its inception, and I saw all the debate around each language feature. These were not made capriciously, but very carefully and thoughtfully. What produced the complexity and difficulty of the resulting language was one thing: backwards compatibility with C. Once you bind yourself to backwards compatibility with anything, you must be prepared for your language to be corrupted as you add features. If Java is unwilling to break backwards compatibility, then it is inevitable that it will acquire both unproductive complexity and incomplete implementation of new features. I've made the case in Thinking in Java 4e that Java Generics are only a pale imitation of real generics, and one of the more appealing suggestions for closures (I think it was called "CPA" but I don't have the notes from that Javapolis talk -- maybe someone can give me the correct name) is an incomplete implementation of true closures, but it would actually be preferable to a complete implementation because it produces clearer, more straightforward code.

Fundamental new features should be expressed in new languages, carefully designed as part of the ecosystem of a language, rather than being inserted as an afterthought. On my radar, the current best exit strategy for Java is Scala. I have even heard some fairly leading-edge programmers say that at this point they didn't care what happens to Java because they were just going to move on to Scala.

If Java is to be saved at all, it needs to become like C; a workhorse that you can rely upon. In fact, any future changes to the language need to be things that simplify and clarify the language and its use (say, fixing the classpath problem), and flesh out (for example) incomplete libraries that have languished (like JMF).

But we need to become especially conservative when considering major, fundamental language features like closures which, while they can be very appealing in theory, may have a cost that is too great in practice when they are forced into a language that values backward compatibility over the clarity of its abstractions.

(We'll be discussing this and other important Java issues at the upcoming JavaPosse Roundup, March 4-7, 2008, in Crested Butte, CO: http://www.mindviewinc.com/Conferences/JavaPosseRoundup/).


Jörn Zaefferer

Posts: 22
Nickname: jzaefferer
Registered: Jul, 2007

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 9:58 AM
Reply to this message Reply
There are two sentences that should be quoted together, closely:

> When you shoehorn a feature into an existing
> language rather than carefully designing it in from the
> beginning, you cannot control how that feature combines
> with other existing features. The combinatorial complexity
> can produce horrifying surprises, typically after the
> feature is added when it's too late to do anything about
> it.[/quote]

> On my radar, the current best exit strategy for Java is
> Scala. I have even heard some fairly leading-edge
> programmers say that at this point they didn't care what
> happens to Java because they were just going to move on to
> Scala.

In other words: Scala is that carefully designed language that had the chance to evolve with only a few people using it - allowing to break backwords compability, because people either simply didn't upgrade (eg. to 2.x) or were eager to upgrade and update their code.

That is another good thought you mention: Why is it that important not to break compability when most Vendors take years to update anyway? I'm developing portlets for IBM Websphere Portal and I'm still stuck on Java 1.4 - which isn't nearly as bad as those pooor buggers who still have to work with 1.3. We ended up writing 90% of our code in Java 5 and getting it down to run on 1.4 using Retrotranslator.

With tools like Retrotranslator I wonder: Why not just break compability and at the same time, offer a tool that just fixes the bytecode to run again? It doesn't seem that hard to do. And I haven't had any issues with Retrotranslator yet, though I guess mostly because all we are using from Java 5 are compiler enhancements like Generics and Autoboxing. Nothing the runtime really cares about.

I haven't yet tried to run Scala on 1.4...

Deron Meranda

Posts: 2
Nickname: dmeranda
Registered: Sep, 2007

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 10:45 AM
Reply to this message Reply
I know you briefly mentioned it, but it is impressive what the Python language designers have been doing with Python 3 (aka Python 3000). The more you understand the language, and its subtle flaws, the more you realize just how impressive and brave the strategy for Python 3 was. It not only breaks backwards compatibility, it gleefully decimates it in some places. The overriding goal for the whole project was to make the language clean and correct, to rethink past mistakes, and to fix them without much regard to compatibility. How well they achieve that is of course debatable, but it can not be said that they were hampered by fearing backwards compatibility.

It will be interesting to see how the Python 3 redesign works out. Perhaps all languages that continue to grow need to eventually do this, and have a point of massive redesign where backwards compatibility concerns are put aware for a while and even the most fundamental designs of the language are seriously questioned again.

Ben Northrop

Posts: 1
Nickname: northrop
Registered: Jan, 2008

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 10:49 AM
Reply to this message Reply
Cool post. I agree that shoe-horning generics into Java resulted in a net loss for the usability/simplicity of the language. I recently bought the O'Reilly book on Generics, and was absolutely blown away by the complexity - and I've been using Java for quite a few years.

It's a tough choice, as you noted. Either...

(a) You shoe-horn the feature and sacrifice the conceptual integrity of the language

(b) You don't add the feature and risk losing market share to newer languages that support it

(c) You add the feature in a very intuitive/simple/powerful way but break backwards compatibility, which IMHO would be a very bad idea - any non-trivial legacy system would be halted in its tracks, since migration would be way too costly/risky

Having worked on a system that was recently upgraded to Java 1.5, I'm very glad that backwards compatibility wasn't broken, since for me life with complex generics constructs is better than life with no generics at all! :)

Jesse Kuhnert

Posts: 24
Nickname: jkuhnert
Registered: Aug, 2006

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 10:51 AM
Reply to this message Reply
So, break backwards compatibility right? If the people making important decisions can decide that not including closures was a mistake maybe they can also conclude that never breaking backwards compatibility is also a mistake.

Java 7 seems like it could go a lot of different ways when it comes out already now that everyone has their hands on it anyways.

Besides, we still need some of the vm enhancements that Neal's proposal (like tail recursion) is putting forward so that we can efficiently run other languages on top of the vm.

If sun wants to still play in the language market after Java loses more market share that is....which I hope they do because we love their vm no matter how much we may curse java. That part of the language has been realized fully and doesn't appear to be one-upped anytime soon. (not even by tamarin, which would be a weird comparison anyways) Of course we'll have to ignore what apple is doing/not doing with the iPhone and os x... ~sigh~

@Bruce
Now that you've targeted Scala as a java successor, I'm curious to know whether you actually like it?

> ...while they can be very appealing in
> theory, may have a cost that is too great in practice when
> they are forced into a language that values backward
> compatibility over the clarity of its abstractions.
>

Frank Sommers

Posts: 2642
Nickname: fsommers
Registered: Jan, 2002

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 10:51 AM
Reply to this message Reply
> It will be interesting to see how the Python 3 redesign
> works out. Perhaps all languages that continue to grow
> need to eventually do this, and have a point of massive
> redesign where backwards compatibility concerns are put
> aware for a while and even the most fundamental designs of
> the language are seriously questioned again.

That brings up an interesting point, something that, I think, Plato also alluded to in the "Ship of Theseus:" At what point is a thoroughly re-designed language the same as the original language, and at what point would you consider that a new language? I think that at some point you need to call that radically rethought language something else, and leave the old language intact, as Bruce writes in this post.

Morgan Conrad

Posts: 307
Nickname: miata71
Registered: Mar, 2006

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 11:35 AM
Reply to this message Reply
I'm fine with minor incompatability issues. Actually, Java *has* had changes that broke code - somebody at our company liked to use "enum" as a variable name. I had to change it in several places. And you can always compile with an older compiler and provide an older JVM. Since many apps are deployed with a specific, well tested JVM, no big issue.

I'd like to see many Java libs "update" to be more compatable with recent changes. For example, JComboBox still has a constructor taking a Vector, but none taking a Collection. For those of you (like me) with short memories, Collection came in in version 1.2, we are now at 1.6. Some of the Apache commons code is getting a little out of date.

For the record, I think Java generics are simple and wonderful 99% of the time, for that annoying 1% just use Objects and cast the old fashioned way...

Eric Rizzo

Posts: 2
Nickname: erizzo
Registered: Oct, 2005

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 11:42 AM
Reply to this message Reply
Thank you for not being afraid to criticize the Java establishment, Bruce. I've been quoting your position on generics for a couple of years and I'm glad to see that you "get" the idea that we'd be better off without them (or any of the new language features) than we are with the choices they've made. My various takes on the subject:
http://bewarethepenguin.blogspot.com/2005/04/price-weve-paid.html
http://bewarethepenguin.blogspot.com/2005/07/java-generics-im-not-alone.html

The epiphany about backwards complexity is a grand one, indeed. I'm starting to see the same problem with Eclipse and it is dismaying because once the attitude of "We Must Not Break Compaitiblity" sets in it is impossible to uproot or even bring up for discussion.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 12:06 PM
Reply to this message Reply
I agree with you Bruce. Here's my argument for why generics were a mistake: in order to understand how they work and why they work the way they do, you basically need to understand how Java worked before generics. That basically implies that a developer new to Java should start with version 1.4 and once confident with that version, move to 1.5 or 1.6.

I'm using 1.5 for a project now and I'm finding myself having to writing things like this to make the compiler happy:

Map<Class<? extends Foo<?>>, List<Bar<? extends Foo<?>>>> map = new HashMap<Class<? extends Foo<?>>, List<Bar<? extends Foo<?>>>>();


I almost feel guilty about it. What a pain for the next developer to try to figure out. It's not that complex but the variance syntax makes it unreadable. Should I do what Morgan suggests and just do it the old way? I'm not sure that's any better.

There were two fundamental flaws in Java from the outset: 1. Stupid variance rules for arrays. 2. No generics.

The first can't be fixed without a major backwards incompatibility and would (I think) be more than just a little change here and there to fix code. The second flaw could not be addressed properly partly because of the first flaw and secondly because it's apparently quite difficult to retrofit generics into a language that didn't support them initially without creating a lot of pitfalls.

Todd Blanchard

Posts: 316
Nickname: tblanchard
Registered: May, 2003

I believe I said that over a year ago Posted: Jan 3, 2008 1:04 PM
Reply to this message Reply
http://www.artima.com/forums/flat.jsp?forum=106&thread=125542

Walter Bright

Posts: 13
Nickname: walterb
Registered: Jul, 2004

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 1:16 PM
Reply to this message Reply
Over at the D programming language, we decided to make 1.0 feature complete, and it only gets bug fixes. With 2.0, we're willing to accept breakage here and there in order to design in the new features right.

Greg Wilson

Posts: 6
Nickname: gvwilson
Registered: Oct, 2005

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 1:16 PM
Reply to this message Reply
I've been following this discussion around the web ever since Steve Yegge's post, and I still want to know: where's the data? People make a lot of claims about language X being more readable than language Y, and about readability having Z impact on productivity/maintainability/bug rates, but I have yet to see a citation of any kind of systematic study. (And yes, I believe it *can* be studied systematically, just as reading acquisition and math comprehension routinely are.)

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 2:04 PM
Reply to this message Reply
> I've been following this discussion around the web ever
> since Steve Yegge's post, and I still want to know:
> where's the data? People make a lot of claims about
> language X being more readable than language Y, and about
> readability having Z impact on
> productivity/maintainability/bug rates, but I have yet to
> see a citation of any kind of systematic study. (And yes,
> I believe it *can* be studied systematically, just as
> reading acquisition and math comprehension routinely are.)

The problem is that such a study is not feasible. You might be able to get a study together to determine comprehension but to get the productivity, maintainability and bug rates isn't going to happen. The best you could do is collect data on what is happening but it's too heterogenous and unreliable. For example, at my last job, my assessment of the failure rate of projects was up near 100% but the official rate was nearly 0%. By what metrics does one even measure maintainability and how do you measure it effectively?

Personally, I'm not of the mind that a study must be done in order to know something. I know I need to breath air to live yet I've never seen a scientific study that proves it. I think I can make an assessment that, let's say, assembly is more costly to work with than Java without a study.

Bob White

Posts: 1
Nickname: milkchaser
Registered: Jan, 2008

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 2:35 PM
Reply to this message Reply
This discussion reminds me of a clique of motorheads whining about how Chevy screwed up the Camaro. Times change. Life goes on.

@SuppressWarnings and <?> cover a multitude of sins.

Morgan Conrad

Posts: 307
Nickname: miata71
Registered: Mar, 2006

Re: Java: Evolutionary Dead End Posted: Jan 3, 2008 3:03 PM
Reply to this message Reply
James - one other trick I've used to simplify things is to define "do nothing interfaces" for better naming (and you can comment the source code interface for the support programmer).

e.g. instead of wrestling with repeated

Bar<? extends Foo<?>>>

define an interface with no methods


/**
* Special interface blah blah you stupid ninny
* I did this to make your pitiful life simpler
*/
interface BarOfFoos extends Bar<? extends Foo<?>>> {
; // this space intentionally left blank
}


This only makes much sense if you are using BarOfFoos in several places in your code. And I think it only works well for interfaces, not classes. I sometimes put these as static interfaces inside the "real" class or interface, so the actual name might end up being Bar.OfFoos. For example, I wrote some nice generic code for events, (cleverly called GenericEvent), and if I then create an actual event class (say FooEvent) you can define, within FooEvent


public static interface Listener extends GenericEvent.Listener<FooEvent> {
; // all done;
}


so you can just write FooEvent.Listener instead of whatever the heck it ends up being with all the <>s and ?s


Apologize for getting off topic, but thought this might help. We should now return to Bruce's post and consider how vital is backwards compatability.

Flat View: This topic has 92 replies on 7 pages [ 1  2  3  4  5  6 | » ]
Topic: Java: Evolutionary Dead End Previous Topic   Next Topic Topic: Can iTunes Accomplish What Jini Couldn't?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use