How will Java 8 impact Kotlin?


#1

Java 8 will not only bring closures to Java, but also extension methods, and with that a variety of extension methods to facilitate functional manipulation of collections (ie. "streams").  Of course Kotlin will still have plenty of great features that aren't planned for Java 8.

For someone implementing a project in Kotlin on JDK 7 today, what will the experience be for migrating to Java 8?  For example, will Kotlin’s versions of Java 8’s new features be compatable with Java 8?


#2

Yes, but Java's "extension methods" serve a different purpose, i.e. parallelization, which is not yet addressed in Kotlin's library


#3

Well, JDK8 lambdas are no true closures, see http://objectscape.blogspot.de/2013/01/jdk8-lambdas-and-anonymous-classes.html They are merely less verbose anonymous classes. That's why Sun/Oracle calls them lambdas and not closures. Nevertheless, they will make things a lot less verbose in Java. Only seeing Spring's HibernateTemplate class at least being re-modeled will remove an enormous amount of boilerplate code ...

Java 8 will not only bring closures to Java, but also extension methods, and with that a variety of extension methods to facilitate functional manipulation of collections (ie. "streams").

I don't really understand this. Those new collection iterators that come in the wake of lambdas are system built-in. You will still not be able to add user-defined extension methods to *locked* system classes as you can in Scala/Kotlin/C# and alike. Then Kotlin has traits and delegates to solve the multiple inheritance problem. To me that is the primary reason why to look for an alternative language to Java. Not being able to model things propperly because of single inheritance in Smalltalk/Java has been a real problem in my developer experience in the last 20 years - much more than not having extension methods (Smalltalk has them, of course).

In my expereince the majority of all Java developers do not know what closures are. In the last 10 years I can hardly remember any Java develpoer that did not respond in a different way than asking what closures are when I complained that Java does not have them. So in about 5 years after the JDK8 has been released the Java masses will start to understand their usefulness. Then a little wave of excitement will break loose and everybody will have to demonstrate the cool things s/he can do with closures. This will take attention away from Groovy/Scala/Kotlin/Ceylon for a while. But that’s fine as we can work in peace during that ime ;-).

Cheers, Oliver


#4

Thanks for the explanation. I have no idea the planned Java 8 lambda is not closure. Man, why do they go only half way.


#5

I think one reason is backwards compatibility. Any pre-JDK8 code that defines a Runnable will still work whether the user does this:

  Thread thread = new Thread(new Runnable() {            @Override            public void run() {            System.out.println("hello world");                       }              });      thread.start();

Or simply this:

new Thread(()-> {System.out.println("hello world");}).start();

Beyond that I'm also disappointed. I don't understand what took them so long when closure variables still need to be declared final (and thus remain on the stack as before). The conclusion to me for this is that the development of Java has come to an end. IMHO it has been put on maintenance. Time to look for new horizons ... :-)

– Oliver


#6

This is misleading, Java 8 lambdas are in fact closures. They do not introduce a new level of scope and do not inherit any names from a supertype. The only limitation compared to Kotlin is the fact that they can only capture effectively final variables. There's a very good reason for this (multi-threaded execution without surprises) and there's also a clear way to work-around it (if you so desire). Kotlin performs the work-around automatically for you and I appreciate that, but that doesn't mean Java's lambdas aren't closures.

Also, Java 8 lambdas are not implemented with anonymous inner classes under the hood. They compile to method handles, so there’s no instantiation overhead.


#7

Yes, I saw that argument coming. That's why I cited Paul Graham in that blog post:

“When a function refers to a variable defined outside it, it’s called a free variable. A function that refers to a free lexical variable is called a closure.”. Paul Graham, ANSI Common Lisp, Prentice Hall, 1996, p.107.

Thus, lambdas without free variables are no closures. I also mentioned the single-element-array trick in my blog:

int sumArray[] = new int[] { 0 };

ints.forEach(i -> {sumArray[0] += i;});

println(sumArray[0]);


Nevertheless, it is ugly.

Kotlin performs the work-around automatically for you and I appreciate that, but that doesn't mean Java's lambdas aren't closures.

I'm not sure about this. The Kotlin guys are bound to the JVM, but this does not prevent them from allocating closure variables on the heap so that they become visible when declared in a context that is an outer context to the closure expression. But I better hold myself back here and let the masters themselves comment on this ...

Here is a really good thread where even Neil Gafter himself tried to explain why inner classes in Java are no closures: http://www.theserverside.com/news/thread.tss?thread_id=57148 The reasoning from Neil Gafter makes me guess that Sun initially had in mind to implement true closures. But that is pure speculation…

There's a very good reason for this (multi-threaded execution without surprises)

This is an interesting point and I tried to talk about it with the Scala guys on their forum for some time ago, but there was no interest. In Java this also doesn't work as the read-only behavior of a final variable can be by-passed with the mentioned single-element-array trick, which is admittedly only true in case the initial developer declared an array, but in many cases the closure variable is often a nested object just like the single-element-array.

Also, Java 8 lambdas are not implemented with anonymous inner classes under the hood. They compile to method handles, so there's no instantiation overhead.

All right, I see. Thanks for this one.

– Oliver


#8

Yes, I read that definition and I don't think that it says anything about mutability. A lambda expression becomes a closure when it's executed within some other scope and captures the variables of that scope (without introducing a new one). A free variable in this context means a non-local (to the lambda) variable, it doesn't mean mutable (or immutable). This closure article on wikipedia seems to agree. Not sure what Neil Gafter said in that post 4 years ago, but yes, inner class instances do not provide closure functionality. Java 8 lambda expressions on the other hand do behave as closures, albeit with a restriction that I can personally live with.

Anyway, this doesn’t change anything about why one would want to use Kotlin over Java. And it’s good that the base JVM language improves, other languages will benefit from good ideas (like SAMs and the Stream APIs) and more powerful JVM features (like indy and method handles).


#9

A free variable in this context means a non-local (to the lambda) variable

Right, I didn't say otherwise.

it doesn't mean mutable (or immutable).

I said that a final variable is still mutable, unlike a simple type (int, float, boolean, etc.) or an immutable one like String, in case it is nested. In that way the lambda variable required to be final for JDK8 lambdas only makes it read-only when not nested or immutable in order to get away with concurrency problems incurred by multi-threading. Groovy has an @Immutable AST transformation which is a nice thing for that purpose.


#10

So to my mind the changes they are bringing in with Java 8 only address a tiny fraction of the issues with Java. In my mind the biggest problem with Java is verbosity, you have to write so much code to do so very little. Although this is annoying from the point of view of writing the code, it's really a lot worse when it comes to reading the code. Trying to pick out the salient features of Java code can be like looking for a needle in a haystack. They is so much 'hay' in the way you can't see the needles, and that is not a good thing for working on big projects with lots of developers touching the same code.

Now as I see it the nice lambda syntax introduced for Java 8 improve that a little bit, but it really doesn’t address the majority of the problem. Look at what Scala and Kotlin are doing for more concise, less cluttered code:

  • Properties, reducing getters and setters - and a more uniform treatment of fields vs methods.
  • Constructor fields as properties, no repeating yourself in your constructors copying parameters into fields.
  • Local type inference, making your code much less cluttered with all that useless type information.
  • In the case of Scala at least, better default accessibility. People almost never want package-private methods/fields so why on earth is it the syntactic default?
  • Cleaner syntax throughout
  • Extension methods/implicit conversions - you can work with classes with a sensible syntax even if you can’t change the class.
  • Support for operators - they can be overused but for some things they are just essential, especially [ ] syntax on collections such as ArrayList.

Plus they remove quite a lot of Java gotchas.

  • Final by default (val vs var, default closed classes, override mandated) only extend something if you really want to do it.
    - Much more support for immutability, and functional programming: less concurrency issues and often cleaner code.
  • Better support for alternative concurrency paradigms: threads are just too painful for general use.

- Switch with default fall through, if you've ever been bitten with that you know it hurts. - In the case of Kotlin, much more careful thought about treatment of nulls. NPEs are so common in Java they even have their own abbreviation!

Does Java 8 address any of these things? Doesn’t seem like it to me … Will Java ever address the majority of these things? I seriously doubt it.


#11

I think a general movement of developers being frustrated with Sun/Oracle and the slow development of Java cannot be undone any more. Even C# is in important language features ways ahead of Java. Changing to M$ is not an option for many developers. I guess it will also take several years in addition till developers can finally make use of JDK8 after it has been released as I don't think it will be installed on production servers that quickly. Till then Kotlin has passed 1.0 for a long time ...


#12

I am still working on java 6. I dont blame java developers although. The thing is that upgrading a runtime environment is quite tricky and scary when you have lots of apps printing money.


#13

Here is an interview with Neal Gafter on Java and C#:

http://www.infoq.com/articles/neal-gafter-on-java

IMHO, it is superb! I’m not sure about Scala, though. It was maybe the only alternative on the JVM at that ime …


#14

That is an interesting interview, I particularly agree with him on support for segmented stacks (or VM coroutines). To my mind that is really holding back the JVM from becoming a platform for highly concurrent applications.

I also think there are a lot of people looking beyond Java. Java is really starting to show its age. But I don’t think the solution is to keep adding more and more features to Java. Every feature needs to be considered with every other, the language needs to fit together as a whole. The key question if you want to add something to a language is “well … what can we take away to make room for this new feature”. And Java can never take away anything, as it would break backwards compatibility.

In my opinion Oracle should probably just essentially declare that Java is “finished now”, no more features for Java. And instead focus their efforts on the thing that people really care about, the JVM Platform. How can they make that platform as useful for as many problems as possible. How can they make it easy for different languages on that platform to interoperate. Currently there are loads of issues with the JVM as a platform: no support for segmented stacks, no support for reified generics, no tail recursion, limited suppor for dynamic languages. All these things are really holding back the platform and limiting its usefulness.


#15

In my opinion Oracle should probably just essentially declare that Java is "finished now", no more features for > Java. And instead focus their efforts on the thing that people really care about, the JVM Platform.

Yeah, I believe a lot of people share that opinion. Looks like the filthy issue about money is the problem here. Once Java is announced deprecated people will start leaving the boat. But that is not why Oracle spent billions on acquiring Sun for. Seems to me that Java was not intended to become the big thing it is today. It took off unexpectedly. So, Oracle doesn’t know whether this will happen with some new “Java done right language” again. However, as soon as Oracle works on a new language for the JVM people will start to abandon the boat as all investments in Java might eventually be lost when the new language pops up. Looks a bit like they are doomed to maintain Java forever. This way they make for sure most money. Another application of game therory ;-). So they continue like that …

– Oliver


#16

Coming to think about it I think JDK8 will mostly come to hit Groovy. When JDK8 has "mostly-closures" then the big added value of Groovy as a language (disregading Grails) is mostly taken again by Java. Groovy will remain really cool to develop DSLs and for scripting. Groovy AST transformations are also very useful. But other added value things in Groovy like Mixins and Delegates are not part of the language, but "only" AST transformations (e.g. at compile time wrapper methods are placed inside the class using the delegate, etc.). The are not true language constructs. Then Groovy has issues with parameterized collections:

public static void main(String[] args)
    {
        def Map<String, Set<String>> map = new HashMap<>()
        def set = new HashSet<String>()
        set.add("foo")
        map.put("bar", set)
        // compiles fine and created runtime error
        // Cannot cast object '[foo]' with class 'java.util.HashSet' to class 'java.util.List'
        // due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for:
        //java.util.List(java.lang.String)
        map.each { Map.Entry<String, List<String>> entry ->
            println(entry.getKey())
            def List<String> list = entry.getValue()
        }
    }

The code above will compile although declared with @CompileStatic, but breaks at runtime. Okay, it is not my job to convert people to one or the other language. But I think Kotlin has an advantage over Groovy being made right from the being not having inherited problems from Java.


#17

Oliver, what you illustrate here is a good definition of the difference between a closure in Groovy and a lambda in Java 8. There are very different beasts. Closures in Groovy are objects that can be coerced to interfaces or classes, while lamdbas are more like method pointers. This means that in Groovy you can manipulate closures while you cannot do that with lambdas. This is where we have the problem of argument type signatures in "type checked" Groovy which will be addressed in a future version.

See https://jira.codehaus.org/browse/GROOVY-5924