3

How can I refer a Lambda from inside of it, if, for example, I need to use myLambda recursively?

myLambda -> {expression}
//           ^^^^^^^^^^ how can I refer to myLambda here?
08Dc91wk
  • 4,254
  • 8
  • 34
  • 67
TooCool
  • 10,598
  • 15
  • 60
  • 85
  • 4
    That's a very backwards way to understand a question. – Sotirios Delimanolis Jan 04 '15 at 16:51
  • 2
    @Abdellah (1) I also wouldn't care much if 10% wouldn't understand my question, but problem is that your question can't be clearly understood by much more than 10% of us and we on Stack Overflow are trying to create library of hight quality question-answers, so question and answers need to be as clear as possible. (2) "like we reference a class with `this`" `this` doesn't refer class, but *instance* of class. – Pshemo Jan 04 '15 at 17:01
  • @Pshemo feel free to correct me if I am wrong. I like to learn from my mistakes :) – TooCool Jan 04 '15 at 17:03
  • I tried to change your question into something clearer, but I am not sure if I didn't change it too much. Feel free to rollback my edit if it is incorrect. – Pshemo Jan 04 '15 at 17:13
  • 3
    It was a deliberate design decision to not support this. As some of the other answers suggest, there are tricks with mutable fields (where lambdas can refer to fields that are uninitialized at time of capture but defined at time of invocation), but these have sharp edges. The key decision was: with the exception of lambda formals, _names have the same meaning inside a lambda as they do outside of it_, including `this`. This is a major simplification over inner classes, whose name-lookup rules are highly complex and error-prone. – Brian Goetz Jan 04 '15 at 18:56

3 Answers3

7

If you mean you want to refer to the lambda expression you're defining within that lambda expression, I don't believe there's any such mechanism. I know of a few cases where it would be useful - recursive definitions, basically - but I don't believe it's supported.

The fact that you can't capture non-final variables in Java makes this even harder. For example:

// This doesn't compile because fib might not be initialized
Function<Integer, Integer> fib = n ->
      n == 0 ? 0
      : n == 1 ? 1
      : fib.apply(n - 1) + fib.apply(n - 2);

And:

// This doesn't compile because fib is non-final
Function<Integer, Integer> fib = null;
fib = n ->
      n == 0 ? 0
      : n == 1 ? 1
      : fib.apply(n - 1) + fib.apply(n - 2);

A Y-combinator would help here, but I don't have the energy to come up with an example in Java right now :(

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
4

I misunderstood your question. Here's how you call a lambda expression recursively :

import java.util.function.*;
public class Test
{
    static Function<Integer, Integer> fib = null;

    public static void main (String[] args)
    {      
        fib = n ->
              n == 0 ? 0
              : n == 1 ? 1
              : fib.apply(n - 1) + fib.apply(n - 2); 
        System.out.println(fib.apply(8));
    }

}

This produces the output 21.

I borrowed the example from Jon Skeet and made the changes required to make it work.

You can find another example of a recursive lambda expression here.

Community
  • 1
  • 1
Eran
  • 387,369
  • 54
  • 702
  • 768
  • 1
    I don't *think* that's what the OP wants - I think he wants to be able to refer to the lambda expression value within it. – Jon Skeet Jan 04 '15 at 16:45
  • To be honest, I have some troubles to understand how this does not produce a NPE. As I understand it, `fib.apply(8)` will try to call `fib.apply(7) + fib.apply(6);` but at that time `fib` is still `null` right? So why don't you get a NPE? – user2336315 Jan 04 '15 at 17:21
  • @Eran Since you didn't answer, I asked the question here FYI: http://stackoverflow.com/questions/27769808/why-calling-this-function-recursively-does-not-throw-a-nullpointerexception – user2336315 Jan 04 '15 at 23:15
1

If you want to define a recursive function, use Java’s canonical way to implement a recursive function: a method:

public static int fib(int n) {
    return n==0? 0: n==1? 1: fib(n-1)+fib(n-2);
}

Then, if you need a instance fulfilling a functional interface you can use a method reference:

Function<Integer, Integer> fib = MyClass::fib;

or

IntUnaryOperator fib0=MyClass::fib;
Holger
  • 285,553
  • 42
  • 434
  • 765