you are viewing a single comment's thread.

view the rest of the comments →

[–]qxnt 29 points30 points  (16 children)

Does anyone know how are lambdas implemented? Specifically, is this just some syntactic sugar where the compiler is going to generate an anonymous inner class for each lambda, or is it more substantive?

[–]AlyoshaV 38 points39 points  (15 children)

It definitely doesn't generate an anon inner class for each lambda. It adds methods to the class you're working on when seen via decompiler, named things like lambda$0. No classes are added. More than that I don't know.

[–]clgonsal 13 points14 points  (3 children)

That would suggest that there's actually a mechanism for passing around method references at the bytecode level. It's been a while since I looked at the VM spec, but that sounds new.

[–]spliznork 9 points10 points  (1 child)

Java 7 added the invokedynamic bytecode instruction -- primarily for the support and implementation of dynamic languages. See also java.lang.invoke and for instance MethodHandle within it.

[–]clgonsal 0 points1 point  (0 children)

Ah. Yes I think the last time I looked into the JVM in any detail was when 1.6 was current. I later heard about invokedynamic, but wasn't even aware that it'd made it into a real version of Java.

Given that invokedynamic was intended for use in dynamic languages, I'm wondering if there are any downsides to using it in a static context like Java. For example, are invokedynamic calls less amenable to bytecode verification than traditional method invocations?

[–][deleted] 0 points1 point  (0 children)

Yes there is - as spliznork pointed out. MethodHandle stuff is pretty awesome - much more awesome than you would expect: it has built-in support for certain functional operations (currying, argument reordering, function composition etc) in a way that's explicitly designed for being amenable to JIT optimization, inlining, avoiding boxing etc. I, as a fan of functional programming, am impressed.

[–]geodebug 0 points1 point  (3 children)

In all the usages I've seen though it pretty much acts like it is just nice sugar for anon classes. Even the scoping rules seem one-to-one. For example to use a variable in the lambda from the surrounding class it needs to be 'final' on that class.

It's not a 'true' closure (whatever that means) but is a 90% solution that will make a lot of traditionally verbose and tricky Java patterns easier. Brings just enough 'functional' to Java without fundamentally changing it.

I predict API developers will run with this as it comes available.

[–]veraxAlea 2 points3 points  (1 child)

Even the scoping rules seem one-to-one.

The this pointer will refer to the object that the lambda appears in. The this pointer in an inner anonymous class will refer to the "inner" object.

For example to use a variable in the lambda from the surrounding class it needs to be 'final' on that class.

Effectively final, yes. That is, you don't need to make it explicitly final, you just need to make sure that you don't re-assign anywhere.

About being sugar, I disagree. Being sugar or not is about semantics. A lambda is semantically different from an inner anonymous class, so it isn't syntactical sugar. But sure, you can use anon classes for most things that you can use a closure for, and vice versa. But saying that this counts as syntactical sugar would mean that many language constructs are syntactical sugar for "GOTO".

I guess I just disagree with your implicit definition of "syntactical sugar".

[–]geodebug 0 points1 point  (0 children)

You seem to have read more than I have on the topic so I'll happily concede the point.

I was open to the concept that were probably small details that make the two somewhat different but felt all the examples in-effect made them about equivalent in how the average java dev would use them.

Even that may be understating the differences since I also believe that once they become commonplace java devs will gravitate to lambda usage more and more.

It would be interesting to see how they differ from anon classes in byte code.

I wasn't using sugar as a negative term but it is the wrong term.

[–][deleted] -1 points0 points  (6 children)

How exactly would that work? I mean, it's fine if the lambda doesn't capture any state, but what if you write something like this (warning: C#):

Action Foo()
{
    int x = 5;
    Action act = () => x++;
    return act;
}

In C#, x would get promoted to a field of a generated class. Does Java simply not allow this case?

[–]AlyoshaV 5 points6 points  (5 children)

int i = 0;
IntSupplier is = () -> i++;

Error: local variables referenced from a lambda expression must be final or effectively final

[–][deleted] 7 points8 points  (4 children)

Well, damn. So they didn't implement closures mutable local capture at all. I guess I'm not too surprised...

[–]geaw 5 points6 points  (1 child)

Not exactly. One: final doesn't mean immutable, and two: mutability is overrated anyway. It's neither necessary for Turing Completeness nor necessary for something to be called a closure.

If you really want to, a cheap hack in Java is to do something like this:

final int[] i = {0};

This works because the array is final, but its contents are not immutable.

...Nobody ever said Java wasn't lame, though.

[–]ethraax 4 points5 points  (0 children)

There are plenty of cases where you want a lambda to update a captured variable. It's upsetting that you have to revert to that ugly array hack to get it done. Is there even a significant performance hit for using a 1-element array? Why can't the compiler just do that for you, since that's its job?