Java 8 – Reasons for Removal of Function Types

functional programmingjavajava8

I have been trying to understand why the JDK 8 Lambda Expert Group (EG) decided not to include a new function type into the Java programming language.

Going over the mailing list I found a thread with the discussion about removal of function types.

Many of the statements are ambiguous to me, maybe because of the lack of context and in some cases because of my limited knowledge on the implementation of type systems.

However, there are a couple of questions that I believe I can safely formulate in this site to help me understand better what they meant.

I know I could ask the questions in the mailing list, but the thread is old and all decisions are already made, so chances are that I will be ignored, above all seeing that these guys are already getting delayed with their plans.

In his answer to support the removal of function types and endorse the use of SAM types, Brian Goetz says:

No reification. There was a long thread about how useful it would be for function types to be reified. Without reification, function
types are hobbled.

I couldn't find the thread he mentions. Now, I can understand that the introduction of a structural function type may imply certain complications in the Java mostly nominal type system, what I cannot understand is how parametrized SAM types are different in terms of reification.

Aren't they both subject to the same reification problems? Does anyone understands how function types are different than parametrized SAM types in terms of reification?

In another comment Goetz says:

There are two basic approaches to typing: nominal and structural. The identity of a nominal is based on its name; the identity of a
structural type is based on what it is composed of (such as "tuple of
int, int" or "function from int to float".) Most languages pick
mostly nominal or mostly structural; there are not a lot of languages
that successfully mix nominal and structural typing except "around
the edges." Java is almost entirely nominal (with a few exceptions:
arrays are a structural type, but at the bottom there is always a
nominal element type; generics have a mix of nominal and structural
too, and this is in fact part of the source of many of people's
complaints about generics.) Grafting a structural type system
(function types) onto Java's nominal type system means new complexity
and edge cases. Is the benefit of function types worth this?

Those of you with experience in the implementation of type systems. Do you know any examples of these complexities or edge cases that he mentions here?

Honestly I get confused by these allegations when I consider that a programming language like Scala, which is entirely based on the JVM, has support for structural types like functions and tuples, even with the reification problems of the underlying platform.

Don't get me wrong, I am not saying that a function type should be better than the SAM types. I just want to understand why they took this decision.

Best Answer

The SAM approach is actually somewhat similar to what Scala (and C++11) do with anonymous functions (created with Scala's => operator or C++11's []() (lambda) syntax).

The first question to answer on the Java side is whether to have the return type of a lambda statement be a new primitve type, like int or byte, or an object type of some sort. In Scala, there are no primitive types -- even an integer is an object of class Int -- and functions are no different, being objects of class Function1, Function2, and so forth, depending on the number of arguments the function takes.

C++11, ruby and python similarly have lambda expressions which return an object which is callable in explicit or implicit way. The returned object has some standard method (such as #call which can be used to call it as a function. C++11, for instance, uses a std::function type which overloads operator() so that calls of the object's call method even look like function calls, textually. :-)

Where the new proposal for Java gets messy is in the use of structural typing to allow assigning such a method to another object, such as a Comparator which has a single main method with a different name. While this is conceptually icky in some ways, it does mean that the resulting object can be passed to existing functions which take an object to represent a callback, a comparator, and so on, and expect to be able to call a well-defined single method such as #compare or #callback. C++'s trick of overriding operator() neatly dodged this issue even before C++11, since all such callback options were callable the same way, and thus the STL required no adjustment to allow C++11 lambdas to be used with sort and so on. Java, not having used a standard naming for such objects in the past (perhaps because no trick like operator overloading made a single approach obvious), isn't so lucky, so this hack prevents them from having to change a whole lot of existing APIs.

Related Topic