Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Is the introduction of the new lambda notation (see e.g. this article) in Java 8 going to require some kind of type inference?

If so, how will the new type system impact the Java language as a whole?

share|improve this question

2 Answers 2

up vote 23 down vote accepted

There's a fair bit of incorrect information in ratchet freak's answer and in its comment thread. I'll respond here in an answer, since a comment is too small. Also, since this an answer after all, I'll attempt to answer the original question too. (Note however that I am not an expert on type systems.)

First, the short answers to the original question are Yes and No. Yes, Java 8 will have considerably more type inference than Java 7, and No, there is not a "new" type system in Java 8, although there are some minor changes.

Java 8 will still be statically typed, and it will still have the dichotomy between classes and interfaces. There are no new types such as function types. The type of a lambda is essentially a "functional interface" which is an ordinary interface with a single abstract method.

Interfaces can now have code in the form of default methods, but the model of single-inheritance of classes and multiple inheritance of interfaces remains the same. There are some adjustments, of course, such as rules for method resolution in the presence of default methods, but the fundamentals are unchanged.

Any type that's inferred by type inference could be written out explicitly. To use ratchet freak's example,

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

is basically sugar for

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

So sparkleshy's statement "type inference doesn't require any extension of the type system" is basically correct.

But to return to syntactic sugar, I'll repeat my statement that a lambda expression is not syntactic sugar for an anonymous inner class. Ratchet freak stated that a lambda expression is translated into an anonymous inner class instantiation, and Sparkleshy simply reasserted that a lambda is syntactic sugar for an anonymous inner class, but these statements are incorrect. They are probably based on outdated information. Early lambda implementations did implement lambdas this way, but things have changed.

Lambda expressions are semantically different from inner classes, and they are implemented differently from inner classes.

Lambda expressions are semantically different from inner classes in a couple ways. Evaluating a lambda expression need not create a new instance each time. They also have different capture semantics, for example, they capture this differently. In an inner class, this is the inner class instance, whereas in a lambda, this is the enclosing instance. Consider the following:

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

In a recent JDK 8 lambda build (I used b69), the output will be something like the following:

CaptureThis$1@113de03
outer

Furthermore, lambda expressions are implemented completely differently from inner classes. If you compare the disassembled output, you'll see that the inner class code straightforwardly compiles to the creation and call to a constructor of CaptureThis$1, whereas the lambda expression compiles to an invokedynamic instruction that procures a Runnable through means unspecified. For a full explanation of how this works and why, see Brian Goetz' JavaOne 2012 talk Lambda: A Peek Under The Hood.

share|improve this answer
2  
"they capture this differently. In an inner class, this is the inner class instance, whereas in a lambda, this is the enclosing instance. Consider the following:" still can be done with syntactic sugar by replacing all this with MyClass.this –  ratchet freak Jan 7 '13 at 2:38
3  
Everything that goes beyond assembler (and sometimes even that) is arguably syntactic sugar. But lambdas are not syntactic sugar for inner classes (any more). They serve a similar goal and have some similarities, but under the hood they are (observably) different. –  Joachim Sauer Jan 7 '13 at 8:29
    
"Lambda expressions are semantically different from inner classes, and they are implemented differently from inner classes.": Thanks for the very good explanation (+1). What is still not clear to me is why have lambdas not been implemented as syntactic sugar for special anonymous classes or, in other words, what is the advantage of the extra complexity introduced by the new semantics? What problem does this solve that cannot be solved with anonymous inner classes? (But I still have to look at the link you posted, maybe I will find the answer there.) –  Giorgio Jan 7 '13 at 10:26
    
@Joachim Sauer: I would consider syntactic sugar a new syntax for an existing semantics. When new semantics is introduced, I think you cannot speak about syntactic sugar. In this sense, I do not think that you can argue that everything beyond assembler is syntactic sugar. –  Giorgio Jan 7 '13 at 10:27
2  
@Giorgio: regarding why lambda isn't just syntactic sugar for anonymous inner classes, turns out there was a large discussion about this. This mail from Brian Goetz summarizes the decision: mail.openjdk.java.net/pipermail/lambda-dev/2011-August/… . TL;DR it leaves the door open for future evolution and we get better performance today. Goetz is actually answering a related question, Are lambdas objects? But if the answer is No or even Maybe that implies they cannot be sugar for inner classes. –  Stuart Marks Jan 8 '13 at 1:22

as I see it it is just syntactic sugar:

to create a lambda you need to have a "functional interface" (only 1 method declared)

to use the old Comparable for use in sorting:

when you do

Collections.<MyClass>sort(list,(a,b)->{return a.order-b.order;});

the compiler will probably translate that directly to

Collections.<MyClass>sort(list,new Comparable<MyClass>(){
         public int compare(MyClass a,MyClass b){return a.order-b.order;}
});

and compile that

the method reference will likely do encompass the static method call in an instance method, so

Collections.<MyClass>sort(list,MyClass::compare);

will be translated to

Collections.<MyClass>sort(list,new Comparable<MyClass>(){
         public int compare(MyClass a,MyClass b){return MyClass.compare(a,b);}
});

this will be just the same as what happens with the variadic argument and it's translation to a array initializer

edit:

even if they don't decide to use anonymous classes or inner classes they could still decide to just use a custom classloader to create the objects that represent the lamba expressions

either by extracting the code in the labmda to its own function or to another class and then passing the method name to a factory that will generate the appropriate code to call said function

the lambda above will then be transformed to

Collections.<MyClass>sort(LambdaFactory.create(Comparator.class, MyClass.class, "lambda$1", new Object{});//the object array is for captured vars

and a new function will be added in MyClass

public static int lambda$1(MyClass a,MyClass b){return a.order-b.order;}

this can be done in 1.6 given enough work the OS project MinecraftForge has done something similar enough. The code for this can be viewed here

share|improve this answer
    
No, it's not the same thing at all. In your first example, the compiler has to figure out that the type of a and b should be MyClass. Nothing of that sort happens when calling a method with variadic arguments. –  sepp2k Nov 30 '12 at 19:53
    
it knows that it has to call the only method of the specified interface, that is the T of Comparable, then the method is called with the T of MyClass, then it is just standard generic extrapolation –  ratchet freak Nov 30 '12 at 19:57
3  
A lambda is decidedly not simply syntactic sugar for an anonymous inner class. (That was one of the early prototype implementations, but it was just a prototype.) For up to date information on lambda, see the documents linked from the following page, in particular the "Translation of Lambda Expressions" document. openjdk.java.net/projects/lambda –  Stuart Marks Dec 5 '12 at 18:19
    
@Stuart Marks: The syntactic-sugar approach would have been the most conservative approach wrt to the language's semantics. I wonder what the impact of a more invasive approach will be. –  Giorgio Dec 30 '12 at 17:44
    
@StuartMarks A lambda is decidedly syntactic sugar for an anonymous inner class. –  sparkleshy Dec 30 '12 at 18:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.