Are Java 8 closures really first-class values or are they only a syntactic sugar?
-
this faq is quite useful for Qs on this subject - http://www.lambdafaq.org/are-lambda-expressions-objects/ – Matt Mar 05 '13 at 11:49
-
1They are definitely not syntactic sugar; see Stuart Marks' answer to this question: http://programmers.stackexchange.com/questions/177879/type-inference-in-java-8 – Maurice Naftalin Mar 05 '13 at 12:32
-
I do not wish to debate on this topic, however there is quite a lot of information available [on the lambda project page](http://openjdk.java.net/projects/lambda/) describing the exact implementation for the JDK, this also covers [virtual extension methods](http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf). – Brett Ryan Mar 07 '13 at 05:30
-
@MauriceNaftalin - Stuart Marks doesn't say they're not syntactic sugar. He says they're "not syntactic sugar for an anonymous inner class". Very different. – Graham Lea Jul 28 '14 at 12:26
-
@GrahamLea Stuart's answer to this question, 1 line below, begins with the words "I would say that Java 8 closures ("Lambdas") are neither mere syntactic sugar nor are they first-class values". Besides, what else would they be sugar for other than aic's? – Maurice Naftalin Jul 30 '14 at 21:06
-
@MauriceNaftalin You're right. I must have been blind that day. Cheers. – Graham Lea Aug 08 '14 at 12:25
5 Answers
I would say that Java 8 closures ("Lambdas") are neither mere syntactic sugar nor are they first-class values.
I've addressed the issue of syntactic sugar in an answer to another StackExchange question.
As for whether lambdas are "first class" it really depends on your definition, but I'll make a case that lambdas aren't really first class.
In some sense a lambda wants to be a function, but Java 8 is not adding function types. Instead, a lambda expression is converted into an instance of a functional interface. This has allowed lambdas to be added to Java 8 with only minor changes to Java's type system. After conversion, the result is a reference just like that of any other reference type. In fact, using a Lambda -- for example, in a method that was passed a lambda expression as parameter -- is indistinguishable from calling a method through an interface. A method that receives a parameter of a functional interface type can't tell whether it was passed a lambda expression or an instance of some class that happens to implement that functional interface.
For more information about whether lambdas are objects, see the Lambda FAQ Answer to this question.
Given that lambdas are converted into objects, they inherit (literally) all the characteristics of objects. In particular, objects:
- have various methods like
equals
,getClass
,hashCode
,notify
,toString
, andwait
- have an identity hash code
- can be locked by a
synchronized
block - can be compared using the
==
and!=
andinstanceof
operators
and so forth. In fact, all of these are irrelevant to the intended usage of lambdas. Their behavior is essentially undefined. You can write a program that uses any of these, and you will get some result, but the result may differ from release to release (or even run to run!).
Restating this more concisely, in Java, objects have identity, but values (particularly function values, if they were to exist) should not have any notion of identity. Java 8 does not have function types. Instead, lambda expressions are converted to objects, so they have a lot baggage that's irrelevant to functions, particularly identity. That doesn't seem like "first class" to me.
Update 2013-10-24
I've been thinking further on this topic since having posted my answer several months ago. From a technical standpoint everything I wrote above is correct. The conclusion is probably expressed more precisely as Java 8 lambdas not being pure (as opposed to first-class) values, because they carry a lot of object baggage along. However, just because they're impure doesn't mean they aren't first-class. Consider the Wikipedia definition of first-class function. Briefly, the criteria listed there for considering functions first-class are the abilities to:
- pass functions as arguments to other functions
- return functions from other functions
- assign functions to variables
- store functions in data structures
- have functions be anonymous
Java 8 lambdas meet all of these criteria. So that does make them seem first-class.
The article also mentions function names not having special status, instead a function's name is simply a variable whose type is a function type. Java 8 lambdas do not meet this last criterion. Java 8 doesn't have function types; it has functional interfaces. These are used effectively like function types, but they aren't function types at all. If you have a reference whose type is a functional interface, you have no idea whether it's a lambda, an instance of an anonymous inner class, or an instance of a concrete class that happens to implement that interface.
In summary, Java 8 lambdas are more first-class functions than I had originally thought. They just aren't pure first-class functions.

- 1
- 1

- 127,867
- 37
- 205
- 259
-
Very good answer, thanks. However I still have some doubts about the meaning of syntactic sugar. For example, in Java the enhanced for loop is converted from the compiler into a regular for loop (hence it's a syntactic sugar) and therefore if a lambda expression is converted into a functional interface why not considering also this conversion as syntactic sugar? – xdevel2000 Mar 06 '13 at 08:21
-
2Depends on your def'n of syntactic sugar, I think. To me, sugar is when the compiler rewrites something for you that you could have written yourself. If you were to write out a lambda as an anonymous inner class, the latter really would have different semantics: it's a real subclass, always creates a new instance, can add fields, can add/override methods, etc. Those don't apply to lambdas. – Stuart Marks Mar 06 '13 at 16:22
-
I think there is some contradiction in what you're saying. First you say: "a lambda expression is converted into an instance of a functional interface" and "To me, sugar is when the compiler rewrites something for you that you could have written yourself" than you say: "... Those don't apply to lambdas.". But a lambda is converted by the compiler into a functional interface... so it's a syntactic sugar! (Also C# and Scala make a conversion...). – xdevel2000 Mar 07 '13 at 08:32
-
@xdevel2000 It is not a syntactic sugar because you couldn't have done by hand a functional interface exactly like the ones that the compiler generates from Closures. One of the main reasons for this is that the bytecode generated for closures are using an instruction (invokedynamic) that is not accessible by any other construct in Java. – Cyrille Ka Mar 08 '13 at 20:57
-
1Cyrille Ka is basically right. To clarify this further, though, I'll say that "conversion" differs from "rewriting". I'm using "conversion" in the sense of type conversion. For example, if we have `Object o = "Hello";` the `String` literal "Hello" is converted into a reference of type `Object`. Rewriting, on the other hand, is transforming a simple syntax in to a more complex syntax that you could have written yourself. Conversion and rewriting are distinct concepts. – Stuart Marks Mar 09 '13 at 07:14
-
One can look at it from a different angle. If Java had no _pure_ values (like in Scala or JavaScript - 1 is an object and `(1).toString()` is a valid expression), Java 8 Lambdas could be considered "real" first class citizens. Boxing/unboxing somewhat addresses this shortcoming of the language. Of course, equals() etc. should be defined and predictable all around - they might be at the time of release. While I agree with your "neither-nor" in general, I think Java lambdas as much closer to first-class than to pure sugar. And in the future (Java 9?) they will be even more 'natural'. – Alex Pakka Oct 24 '13 at 18:08
-
1Fair points. The notion of "first-class" is pretty subjective. Boxing/unboxing helps give the illusion of value types, but unfortunately the underlying primitive/reference dichotomy shows through at odd times. Consider comparing two boxed Integers using `<=` versus `==`, for example. But, overall, I've also been thinking more about this topic recently, and I'll update my answer shortly. – Stuart Marks Oct 24 '13 at 21:09
-
@CyrilleKa: Bytecode is a runtime/implementation level concern. From a pure language point of view, any lambda expression can be re-written into an anonymous class creation expression and have the same effect. – newacct Oct 25 '13 at 09:00
-
@newacct That's for a different definition of "the same effect". I don't consider `switch` to be a syntactic sugar for a bunch of `if` either, even though any `switch` can be transformed into a few `if`s. Or consider OOP: any class with instance methods can be rewritten to a struct-like class with static methods taking an instance as the first parameter. It doesn't mean OOP is mere syntactic sugar: internally it's very different, and it shows in reflection. All this is a question of semantics, anyway. We can disagree on the definition of syntactic sugar. I feel yours is too broad to be useful. – Cyrille Ka Oct 25 '13 at 15:02
-
-
1Declare a value of the functional interface type, including generics. For example, `Function
fn = s -> s.toUpperCase();` – Stuart Marks Feb 21 '14 at 01:50 -
given an existing method (not function) like `class C { static int f() { return 1; }`, can i pass `C.f` to a mocker or something? is there a way to do this? – sam boosalis May 28 '14 at 19:42
-
1@samboosalis I'm not entirely sure what passing a function to a mocker would need to do, but you can do something like this using method references. Since your existing method takes no parameters and returns an int, it conforms to the `IntSupplier` functional interface. You could then pass `C::f` to anything that takes an `IntSupplier`. This isn't really passing a reference directly to the `f()` method, it's sugar for a lambda `() -> C.f()` that calls the `f()` method. But it should be close enough for most purposes. – Stuart Marks May 29 '14 at 00:22
-
that's what i was afraid of. i guess my point is that methods are still second-class, while functional interfaces exist that act like first class functions. i just wanted to give a common example use case: a unittest that mocks out a method. if methods were just fields whose values are functions, you could swap them with anything that shares the type. you're saying a `C::f` syntax exists for making a functional interface from a method, which is cool. but i still can't mock out methods as easily as in python. thanks! – sam boosalis May 29 '14 at 00:44
-
1Yep, methods are still methods. If you want to mock one out, you have to do something like creating a dynamic proxy, which is what I think the mocking frameworks do. – Stuart Marks May 29 '14 at 06:52
Yes, they are first class values (or will be, once Java 8 is released...)
In the sense that you can pass them as arguments, compose them to make higher order functions, store them in data structures etc. You will be able to use them for a broad range of functional programming techniques.
See also for a bit more definition of what "first class" means in this context:

- 105,238
- 25
- 256
- 415
As I see it, it is syntactic sugar, but in addition with the type inference, a new package java.util.functions
and semantic of inner classes it does appear as a first-class value.

- 28,279
- 7
- 71
- 101
A real closure with variable binding to the outside context has some overhead. I would consider the implementation of Java 8 optimal, sufficiently pure.
It is not merely syntactical sugar at least.
And I wouldn't know of any more optimal implementation.

- 107,315
- 7
- 83
- 138
For me Lambdas in Java 8 is just syntax sugar because you cannot use it as First class Citizen (http://en.wikipedia.org/wiki/First-class_function) each function should be wrapped into object it imposes many limitation when comparing to language with pure first class function like SCALA. Java 8 closures can only capture immutable ("effectively final") non-local variables.
Here is better explanation why it is syntax-sugar Java Lambdas and Closures

- 1
- 1

- 7,513
- 4
- 62
- 67