4

According to JLS 15.27.2 the lambda body has the same scope as the surrounding context and I would like to know if there is a specific reason to why default methods from the interface that is implemented by the lambda aren't available within the body too? Does this restriction enable some optimization or is it just to keep the overload rules simple?

I was prototyping some Java 8 API today and when I hit this limitation I was pretty disappointed because using default methods would have allowed me to implement that API in a very elegant and non-intrusive way.

Achieving the same elegancy is more or less possible by requiring a static import, but that results in "polluting" the namespace.

Is there a chance that this restriction will be lifted?

ManoDestra
  • 6,325
  • 6
  • 26
  • 50
Christian Beikov
  • 15,141
  • 2
  • 32
  • 58
  • a short example would be helpful to understand what you are talking about – AdamSkywalker Apr 14 '16 at 16:05
  • 1
    Related (though not a duplicate): http://stackoverflow.com/q/33108540/3973077 – Paul Boddington Apr 14 '16 at 16:06
  • 1
    “*the lambda body has the same scope as the surrounding context*” already implies that there are no spurious `default` methods in scope. Of course, this simplifies the name resolution rules a lot. And it all boils down to the mantra “*lambda expressions are not syntactic sugar for inner classes*”… See also [here](http://stackoverflow.com/a/31491773/2711488) – Holger Apr 14 '16 at 16:26
  • The related question actually includes a good example. – Christian Beikov Apr 14 '16 at 17:16
  • @Holger: Thanks, that is a really helpful answer! Instantiation performance and other possible optimizations are very good reasons! Just too bad that there isn't a lambda variant that also allows the use of default methods :( – Christian Beikov Apr 14 '16 at 17:27
  • 1
    Possible duplicate of [Can a lambda access members of its target functional interface?](http://stackoverflow.com/questions/28780755/can-a-lambda-access-members-of-its-target-functional-interface) – fps Apr 15 '16 at 01:26
  • You can always write a Y-Combinator (yes, it works.) – Brian Goetz Apr 21 '16 at 02:31

1 Answers1

5

The default methods aren't available to the lambda, because the lambda has not yet been given a type until it is assigned to a functional type. For example, the lambda

s -> s.isEmpty()

could be assigned to a java.util.function.Predicate or a com.google.common.base.Predicate. For that reason it doesn't have access to java.util.function.Predicate's default methods until it is actually assigned to a java.util.function.Predicate by direct assignment to a java.util.function.Predicate, by passing the lambda as a java.util.function.Predicate parameter, returning it from a function whose return type is java.util.function.Predicate, or simply casting it to a java.util.function.Predicate like this:

((Predicate<String>) s -> s.isEmpty()).negate();   // negate is a default method on Predicate

One way to think of it is being analogous to boxing an int value. Integer's methods can't be called on a literal integer value, but once the integer value is assigned to an Integer type, one can call its methods.

Hank D
  • 6,271
  • 2
  • 26
  • 35
  • 1
    Well I don't see how that is a reason. I don't know how the compiler is implemented but since the lambda type is inferred from the LHS the compiler should already know the type when it checks the lambda body. – Christian Beikov Apr 14 '16 at 17:11
  • 2
    I see your point, and I don't intend to defend the compiler design. My understanding, FWIW, is that a lambda is a body without a signature and a functional interface is a signature without a body, and it isn't until the assignment or cast that the two are joined and an actual function gets generated. Hope that helps. – Hank D Apr 14 '16 at 18:01