Sunday, 14 March 2010

Java language design by use case

In a blog in 2006 Neal Gafter wrote about how language design was fundamentally different to API design and how use cases were a bad approach to language design. This blog questions some of those conclusions in the context of the Java language.

Java language design by use case

Firstly, Neal doesn't say that use cases should be avoided in language design:

In a programming language, on the other hand, the elements that are used to assemble programs are ideally orthogonal and independent. ...
To be sure, use cases also play a very important role in language design, but that role is a completely different one than the kind of role that they play in API design. In API design, satisfying the requirements of the use cases is a sufficient condition for completeness. In language design, it is a necessary condition.

So, Neal's position seems very sound. Language features should be orthogonal, and designed to interact in new ways that the language designer hadn't thought of. This is one element of why language design is a different skill to API design - and why armchair language designers should be careful.

The problem, and the point of this blog, is that it would appear that the development of the Java language has never been overly concerned with following this approach. (I'm not trying to cast aspersions here on those involved - just trying to provide some background on the language).

Consider inner classes - added in v1.1. These target a specific need - the requirements of the swing API. While they have been used for other things (poor mans closures), they weren't overly designed as such.

Consider enums - aded in v1.5. These target a single specific use case, that of a typesafe set of values. They don't extend to cover additional edge cases (shared code in an abstract superclass or extensibility for example) because these weren't part of the key use case. JSR-310 has been significantly compromised by the lack of shared code.

Consider the foreach loop - added in v1.5. This meets a single basic use case - looping over an array or iterable. The use case didn't allow for indexed looping, finding out if its the first or last time around the loop, looping around two lists pairwise, and so on. The feature is driven by a specific use case.

And the var-args added in v1.5? I have a memory that suggests the use case for its addition was to enable String printf.

Finally, by accounts I've heard, even James Gosling tended to add items to the original Java builds on the basis of what he needed at that moment (a specific use case) rather than to a great overarching plan for a great language.

To be fair, some features are definitely more orthogonal and open - annotations for example.

Looking forward, Project Lambda repeats this approach. It has a clear focus on the Fork-Join/ParallelArray use case - other use cases like filtering/sorting/manipulating collections are considered a second class use case (apparently - its a bit hard to pin down the requirements). Thus, once again the Java language will add a use case driven feature rather than a language designers orthogonal feature.

But is that necessarily a Bad Thing?

Well, firstly we have to consider that the java language has 9 million developers and is probably still the worlds most widely used language. So, being use case driven in the past hasn't overly hurt adoption.

Now, most in the community and blogosphere would accept that in many ways Java is actually not a very good programming language. And somewhere deep down, some of that is due to the use case/feature driven approach to change. Yet, down in the trenches most Java developers don't seem especially fussed about the quality of the language. Understanding that should be key for the leaders of the Java community.

I see two ways to view this dichotomy. One is to say that it is simply because people haven't been exposed to better languages with a more thought through and unified language design. In other words - once they do see a "better designed language" they'll laugh at Java. While I think that is true of the blogosphere, I'm rather unconvinced as to how true that is of the mainstream.

The alternative is to say that actually most developers can more easily handle discrete use-case focussed language features better than abstracted, independent, orthogonal features. In other words - "use feature X do achieve goal Y". I have a suspicion that is how many developers actually like to think.

Looked at in this way, the design of the Java language suddenly seems a lot more clever. The use case driven features map more closely onto the discrete mental models of working developers than the abstract super-powerful ones of more advanced languages. Thus this is another key difference that marks out a blue collar language (pdf) (cache) from an academic experiment.

Project Lambda

I'm writing this blog because of Project Lambda, which is adding closures to the Java language. Various options have been suggested to solve the problem of referring to local variables and whether those reference should be safe across multiple threads or not. The trouble is that there are two use cases - immediate invocation, where local variables can be used immediately and safely, and deferred asynchronous invocation where local variables would be published to another thread and be subject to data races.

What this blog suggests is that maybe these two use cases need to be representable as two language features or two clear variations of the same feature (as in C++11).

Summary

Many of the changes to the Java language, and some of the original features, owe as much to a use case driven approach as to an overarching language design with orthogonal features. Yet despite this supposed "flaw" developers still use the Java language in droves.

Maybe its time to question whether use case focus without orthogonality in language features isn't such a Bad Thing after all?

Feedback welcome!

16 comments:

  1. Developers choose a language not just based on the design of the language itself but the availability of libraries and frameworks to help on solving the task at hand. This has traditionally been a strong point for Java.

    ReplyDelete
  2. Lawrence Kesteloot15 March 2010 at 05:25

    What are the two popular orthogonal languages? Lisp and Smalltalk. Rounded to the nearest percent, what percent of commercial software is written in either? 0%. I assert (unprovably) that their orthogonality is why they're so unpopular amongst programmers. A language is like an API and like a UI. Orthogonality hurts. I've written about this before here, with examples:

    http://www.teamten.com/lawrence/writings/the_language_squint_test.html

    "It’s the orthogonality of Lisp, ironically, that results in programmers not benefiting from a powerful part of their brain."

    ReplyDelete
  3. Some times, the use case is the problem. For as long as Gilad, Neal, etc were speaking about the difficulty of adding generics back in 1.5, the major issue that lead to the type-erasure implementation was the fact that they couldn't make type assertions about arrays, due to the one use case that they felt they had to allow in the original versions of java:

    Object[] arr = new String[]{};

    ReplyDelete
  4. Isn't the "use case" obvious? It's to reduce boilerplate code. To ensure the prime directive of "not repeating yourself" is followed as much as possible.

    Use cases sound nice when building a product or API, but "language design" may take some deeper / higher level thinking to get right. I wouldn't know though, since I've not done any language design.

    Are you speaking from personal experience or just pointing out what you think the java language designers were doing when implementing various features?

    ReplyDelete
  5. I think we must distinct the concept of a syntactic sugar (multicatch, automatic resource detection and a "foreach" statement) and the concept of new language feature - lambda expressions.

    ReplyDelete
  6. Should we be continuing to design by use case, or should we work on developing useful orthagonal language features? Consider inner classes, which were designed by use case for Swing. Shouldn't they have added closures for Swing, and avoided the kludge and boilerplate of inner classes as poor-man's closures to begin with?

    ReplyDelete
  7. "...most Java developers don't seem especially fussed about the quality of the language".

    I believe that a lack of language quality can to some degree be compensated by quality tools. And the Java environment spawned quality tools, amongst them Eclipse.
    When a developer is accustomed to tools supporting him with features like a working code completion, refactoring, or code generation the barrier of adopting a new language that does not have this tooling support is quite high. An example might be Scala, where the Scala Plug-In for Eclipse is by far not as mature as JDT.

    ReplyDelete
  8. Stephen Colebourne16 March 2010 at 10:25

    Lots of good comments. One point I'd note is that BGGA demonstrated that one orthogonal feature (full closures) could replace many use-case-driven ones (ARM, foreach, synchronized, inner class, ...). My open question was whether that necessarily made the language easier to use (the orthogonal feature is undoubtably more powerful).

    ReplyDelete
  9. To answer Stehphen's last question - "yes". At least in other languages. The concept isn't new, as everyone is well aware.

    ReplyDelete
  10. You offer two alternatives for why Java's popular, but there's a third possibility: That Java developers are familiar with other languages which often don't have enough features (C) or have the same features but poorly implemented (C++). Take enums, for example. Both C and C++ enums are just sugar-coated ints, and the JDK1.5 release notes clearly explain why they suck. Or take virtually *any* C/C++ feature - pointers, templates, function pointers, multiple inheritence, etc. In each case, Java does it better or not at all. Gosling has commented that Stroustrup would probably do a lot of things differently if he were to start over, and Stroustrup replied that he wouldn't change anything at all. There comes a point where a language designer just can't see language ugliness anymore because it all looks straightforward. It's not so much about using use cases or not. The C/C++ enum use case is the same as the Java enum use case, but they're entirely different designs. It's the same with closures - all the proposals seem to cover most use cases, but some proposals are just plain ugly.

    ReplyDelete
  11. There is a good rule of thumb in design. Do not freeze it until it has been used in three sufficiently different situations.

    I think use case based approach is reasonably pragmatic. But please can new language feature be applied to more use cases than just FJ/PA before being frozen.

    This does not necessarily mean the feature should be orthogonal. Just make it usable in more than one context. Even foreach loop works with: a) arrays and b) iterables.

    ReplyDelete
  12. You've misquoted my article. I didn't say that "use cases were a bad approach to language design". I said that there is a particular (bad) way in which use cases could be used to direct a language design, and other (good) ways in which use cases could be used to direct a language design. You don't seem to have recognized the distinction between the two.

    ReplyDelete
  13. @Stephen & Jesse
    "Easier" is not as simple as it may appear...
    My son had spent hours/days agonising about learning to cycle. Now he would say "it's eeeasy!". There seems to be an invisible [learning?] barrier between something being hard to becoming easy.
    So, in the BGGA case, once you learn how to use it, it can become "eeeasy!".
    However, there may be a [mental capacity] cost. I can juggle while I walk - I find juggling while cycling nearly impossible.
    So, it's all about the balance with the associated benefit.

    ReplyDelete
  14. Stephen Colebourne18 March 2010 at 12:16

    @Neal, I both paraphrased and quoted your article, using it to make my own point - Java doesn't have that many orthogonal additions, and maybe thats one reason for its success.

    ReplyDelete
  15. The current revival of closures proposals is mostly driven by the difficulty to use a ParallelArray API in Java.

    If the use case is parallel programming, then attempts at making Java a functional language seem out of scope. Better concentrate on constructs for expressing parallelism, they make parallel code both simpler and more expressive. Examples here: http://ateji.blogspot.com/

    ReplyDelete
  16. liked much the link to the "squint test" in this discussion. though language designers are often clever people with their head full of new paradigms I feel their syntactic choices are more driven by personal fancy than by an experimental approach on how programmers will grasp the structure of their code. for sure there are other structural reasons for syntactic choices but I feel that syntactic "ergonomy" is an insufficiently studied field.

    ReplyDelete