Softly softly

Language design is subtle

Lukas Eder
angle

Java may not have the “cool” clout of node.js – but, as Lukas Eder argues, it’s more important to think long-term, putting things like backwards-compatibility to the fore.

This post was originally published over at jooq.org as part of a special series
focusing on all things Java 8, including how take advantage of
lambda expressions, extension methods, and other great
stuff. You’ll find the
source code on GitHub
.

It’s been a busy time for us. We have just migrated
the 
jOOQ integration tests to
Java 8 for two reasons:

  • We want to be sure that client code compiles with Java 8
  • We started to get bored of writing the same old loops over and
    over again

The trigger was a loop where we needed to transform
SQLDialect[] into
another SQLDialect[] calling .family() on
each array element. Consider:

Java 7

SQLDialect[] families =
    new SQLDialect[dialects.length];
for (int i = 0; i < families.length; i++)
    families[i] = dialects[i].family();

Java 8

SQLDialect[] families =
Stream.of(dialects)
      .map(d -> d.family())
      .toArray(SQLDialect[]::new);

OK, it turns out that the two solutions are equally verbose,
even if the latter feels a bit more elegant. :-)

And this gets us straight into the next topic:

Backwards-compatibility

For backwards-compatibility reasons, arrays and the pre-existing
Collections API have not been retrofitted to accommodate all the
useful methods that Streams now have. In other words, an array
doesn’t have amap() method, just as much
as List doesn’t have such a method. Streams
and Collections/arrays are orthogonal worlds. We can transform them
into each other, but they don’t have a unified API.

This is fine in everyday work. We’ll get
used to the Streams API and we’ll love it
, no doubt. But
because of Java being extremely serious about backwards
compatibility, we will have to think about one or two things more
deeply.

Recently, we have published a post about The
Dark Side of Java 8
. It was a bit of a rant, although a mild
one in our opinion (and
it was about time to place some criticism, after all the praise
we’ve been giving Java 8 in our series,
before
 ;-) ). First off, that post
triggered a
reaction by Edwin Dalorzo from our friends at Informatech
.
(Edwin has written this awesome
post comparing LINQ and Java 8 Streams, before
). The criticism
in our article evolved around three main aspects:

  • Overloading getting more complicated (see also this compiler
    bug
    )
  • Limited support for method modifiers on default methods
  • Primitive type “API overloads” for streams and functional
    interfaces

A response by Brian Goetz

I then got a personal mail from no one less than Brian Goetz himself (!),
who pointed out a couple of things to me that I had not yet thought
about in this way:

I still think you’re focusing on the wrong thing. Its not really
the syntax you don’t like; its the model — you don’t want “default
methods”, you want traits, and the syntax is merely a reminder that
you didn’t get the feature you wanted. (But you’d be even more
confused about “why can’t they be final” if we dropped the
“default” keyword!) But that’s blaming the messenger (where here,
the keyword is the messenger.)

Its fair to say “this isn’t the model I wanted”. There were many
possible paths in the forest, and it may well be the road not taken
was equally good or better.

This is also what Edwin had concluded. Default methods were a
necessary means to tackle all the new API needed to make Java 8
useful. If IteratorIterableListCollection,
and all the other pre-existing interfaces had to be adapted to
accommodate lambdas and Streams API interaction, the expert group
would have needed to break an incredible amount of API. Conversely,
without adding these additional utility methods (see
the awesome new Map methods, for instance!
), Java 8 would have
been only half as good.

And that’s it.

Even if maybe, some more class building tools might have been
useful, they were not in the center of focus for the expert group
who already had a lot to do to get things right. The center of
focus was to provide a means for API evolution. Or in Brian Goetz’s
own words:

Reaching out to the community

It’s great that Brian Goetz reaches out to the community to help
us get the right picture about Java 8. Instead of explaining
rationales about expert group decisions in private messages, he
then asked me to publicly re-ask my questions again on Stack
Overflow (or lambda-dev), such that he can then publicly answer
them. For increased publicity and greater community benefit, I
chose Stack Overflow. Here are:

The amount of traction these two questions got in no time shows
how important these things are to the community, so don’t miss
reading through them!

“Uncool”? Maybe. But very stable!

Java may not have the “cool” aura that node.js has. You may think about
JavaScript-the-language whatever you want (as long as it contains
swear words), but from a platform marketing perspective, Java is
being challenged for the first time in a long time – and being
“uncool” and backwards-compatible doesn’t help keeping developers
interested.

But let’s think long-term, instead of going with trends. Having
such a great professional platform like the Java language, the JVM,
the JDK, JEE, and much more, is invaluable. Because at the end of
the day, the “uncool” backwards-compatibility can also be awesome.
As mentioned initially, we have upgraded our integration tests to
Java 8. Not a single compilation error, not a single bug.
Using Eclipse’s
BETA support for Java 8
, I could easily transform anonymous
classes into lambdas and write awesome things like these
upcoming jOOQ 3.4
nested transactions (API not final yet):

ctx.transaction(c1 -> {
    DSL.using(c1)
       .insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME)
       .values(3, "Doe")
       .execute();
 
    // Implicit savepoint here
    try {
        DSL.using(c1).transaction(c2 -> {
            DSL.using(c2)
               .update(AUTHOR)
               .set(AUTHOR.FIRST_NAME, "John")
               .where(AUTHOR.ID.eq(3))
               .execute();
 
            // Rollback to savepoint
            throw new MyRuntimeException("No");
        });
    }
 
    catch (MyRuntimeException ignore) {}
 
    return 42;
});

So at the end of the day, Java is great. Java 8 is a tremendous
improvement over previous versions, and with great people in the
expert groups (and reaching out to the community on social media),
I trust that Java 9 will be even better. In particular, I’m looking
forward to learning about how these two projects evolve:

Although, again, I am really curious how they will pull these
two improvements off from a backwards-compatibility perspective,
and what caveats we’ll have to understand,
afterwards. ;-)

Anyway, let’s hope the expert groups will continue to provide
public feedback on Stack Overflow. Stay tuned for more awesome Java 8
content
!

Author
Lukas Eder
Lukas is a Java and SQL aficionado. He’s the founder and head of R&D at Data Geekery GmbH, the company behind jOOQ, the best way to write SQL in Java.
Comments
comments powered by Disqus