12
votes

I read from an interview with Neal Gafter:

"For example, adding function types to the programming language is much more difficult with Erasure as part of Generics."

EDIT: Another place where I've met similar statement was in Brian Goetz's message in Lambda Dev mailing list, where he says that lambdas are easier to handle when they are just anonymous classes with syntactic sugar:

But my objection to function types was not that I don't like function types -- I love function types -- but that function types fought badly with an existing aspect of the Java type system, erasure. Erased function types are the worst of both worlds. So we removed this from the design.

Can anyone explain these statements? Why would I need runtime type information with lambdas?

4
this would be better answered on programmers.stackexchange.comuser177800
great question - I have been wondering the same thing after Goetz's comment.sourcedelica

4 Answers

7
votes

The way I understand it, is that they decided that thanks to erasure it would be messy to go the way of 'function types', e.g. delegates in C# and they only could use lambda expressions, which is just a simplification of single abstract method class syntax.

Delegates in C#:

public delegate void DoSomethingDelegate(Object param1, Object param2);
...
//now assign some method to the function type variable (delegate)
DoSomethingDelegate f = DoSomething;
f(new Object(), new Object());

(another sample here http://geekswithblogs.net/joycsharp/archive/2008/02/15/simple-c-delegate-sample.aspx)

One argument they put forward in Project Lambda docs:

Generic types are erased, which would expose additional places where developers are exposed to erasure. For example, it would not be possible to overload methods m(T->U) and m(X->Y), which would be confusing.

section 2 in: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html

(The final lambda expressions syntax will be a bit different from the above document: http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/003936.html)

(x, y) => { System.out.printf("%d + %d = %d%n", x, y, x+y); }

All in all, my best understanding is that only a part of syntax stuff that could, actually will be used. What Neal Gafter most likely meant was that not being able to use delegates will make standard APIs more difficult to adjust to functional style, rather than that javac/JVM update would be more difficult to be done.

If someone understands this better than me, I will be happy to read his account.

2
votes

Goetz expands on the reasoning in State of the Lambda 4th ed.:

An alternative (or complementary) approach to function types, suggested by some early proposals, would have been to introduce a new, structural function type. A type like "function from a String and an Object to an int" might be expressed as (String,Object)->int. This idea was considered and rejected, at least for now, due to several disadvantages:

  • It would add complexity to the type system and further mix structural and nominal types.
  • It would lead to a divergence of library styles—some libraries would continue to use callback interfaces, while others would use structural function types.
  • The syntax could be unweildy, especially when checked exceptions were included.
  • It is unlikely that there would be a runtime representation for each distinct function type, meaning developers would be further exposed to and limited by erasure. For example, it would not be possible (perhaps surprisingly) to overload methods m(T->U) and m(X->Y).

So, we have instead chosen to take the path of "use what you know"—since existing libraries use functional interfaces extensively, we codify and leverage this pattern.

To illustrate, here are some of the functional interfaces in Java SE 7 that are well-suited for being used with the new language features; the examples that follow illustrate the use of a few of them.

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.util.Comparator
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener
  • ...

Note that erasure is just one of the considerations. In general, the Java lambda approach goes in a different direction from Scala, not just on the typed question. It's very Java-centric.

1
votes

Maybe because what you'd really want would be a type Function<R, P...>, which is parameterised with a return type and some sequence of parameter types. But because of erasure, you can't have a construct like P..., because it could only turn into Object[], which is too loose to be much use at runtime.

This is pure speculation. I am not a type theorist; i haven't even played one on TV.

-1
votes

I think what he means in that statement is that at runtime Java cannot tell the difference between these two function definitions:

void doIt(List<String> strings) {...}
void doIt(List<Integer> ints) {...}

Because at compile time, the information about what type of data the List contains is erased, so the runtime environment wouldn't be able to determine which function you wanted to call.

Trying to compile both of these methods in the same class will throw the following exception:

doIt(List<String>) clashes with doIt(List<Integer); both methods have the same erasure