Bug 484032 - [1.8] Stack frame for Lambda doesn't provide enough context in Variables view
Summary: [1.8] Stack frame for Lambda doesn't provide enough context in Variables view
Status: CLOSED DUPLICATE of bug 516278
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 4.6   Edit
Hardware: PC Windows 7
: P3 normal with 1 vote (vote)
Target Milestone: 4.8   Edit
Assignee: Sarika Sinha CLA
QA Contact:
URL:
Whiteboard: goal
Keywords:
Depends on:
Blocks: 521038
  Show dependency tree
 
Reported: 2015-12-09 11:04 EST by Markus Keller CLA
Modified: 2017-12-11 05:53 EST (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2015-12-09 11:04:40 EST
I20151207-2000

The stack frame for a Lambda doesn't provide enough context in the debugger.

Example:

package xy;
public class LambdaDebugging {
    public static void main(String[] args) {
        String message = "Hello World";
        
        Thread thread= new Thread() {
            @Override
            public void run() {
                System.out.println(message); // Breakpoint
            }
        };
        thread.start();
        Runnable runnable= () -> {
            System.out.println(message); // Breakpoint
            System.out.println(message + 2);
        };
        runnable.run();
    }
}

In the lambda, I can't write a breakpoint condition that refers to the variable 'message', e.g. 'message.contains("or")'. Content assist supports 'message', but when the breakpoint is hit, I get a Conditional Breakpoint Error (message cannot be resolved).

It's also hard to debug the lambda body, because the Variables view only shows the captured local variables when the second stack frame is selected:

Debug view;

  LambdaDebugging.lambda$0(String) line: 14	
  104739310.run() line: not available	
  LambdaDebugging.main(String[]) line: 17	

Variables view (selection: 104739310.run()...):

  this= 104739310  (id=30)	
    arg$1= "Hello World" (id=31)

If the debug protocol doesn't provide more information in the topmost stack frame, then JDT Debug may have to inject a custom "this" with properly named children (e.g. val$message or arg$message instead of arg$1).

This should also be used in the Variable Values hover, which also doesn't work when a thread is suspended in a lambda body.
Comment 1 Jesper Moller CLA 2016-03-29 15:53:01 EDT
Bug 422015 also contains some discussion of this problem.

The problem here is that the function object created by the lambda metafactory is an implementation detail of the runtime, and even the order of the captured variables ('messages' in this case) is a compiler implementation detail. Yes, we can make assumptions about either, but we can't guarantee that it would continue to work in the future.
Comment 2 Jesper Moller CLA 2016-03-29 17:43:29 EDT
Another thing: The Variable Values hover does work for lambda expressions, just not for captured variables in the lambda expressions outer scope. Consider this class, paused at breakpoint 3. Here will both 'lambdaParameter' and 'this.instanceField' show contents on hovering, but 'effectivelyFinal' and 'effectivelyFinalMethodParameter' will not:

import java.util.function.Consumer;

public class LambdaDebugging {
	
	public static String staticField = "Static Field";
	public String instanceField = "Instance Field";
	
    public static void main(String[] args) {
        new LambdaDebugging().someMethod("Effectively Final Method Parameter");
    }
    void someMethod(String effectivelyFinalMethodParameter) {
        String effectivelyFinal = "Effectively Final";
        
        Consumer<String> anonymousConsumer = new Consumer<String>() {
            public void accept(String parameter) {
                System.out.println("effectivelyFinalMethodParameter is '" + effectivelyFinalMethodParameter + "'"); // Breakpoint 1
                System.out.println("effectivelyFinal is '" + effectivelyFinal + "'");
                System.out.println("parameter is '" + parameter + "'");
            }
        };
        anonymousConsumer.accept("Parameter");
        
        Consumer<String> staticLambda = (lambdaParameter) -> {
        	System.out.println("effectivelyFinalMethodParameter is '" + effectivelyFinalMethodParameter + "'"); // Breakpoint 2
            System.out.println("effectivelyFinal is '" + effectivelyFinal + "'");
            System.out.println("lambdaParameter is '" + lambdaParameter + "'");
        };
        staticLambda.accept("Lambda Parameter");
 
        Consumer<String> instanceLambda = (lambdaParameter) -> {
        	System.out.println("effectivelyFinalMethodParameter is '" + effectivelyFinalMethodParameter + "'"); // Breakpoint 3
            System.out.println("effectivelyFinal is '" + effectivelyFinal + "'");
            System.out.println("lambdaParameter is '" + lambdaParameter + "'");
            System.out.println("instanceField is '" + this.instanceField + "'");
        };
        instanceLambda.accept("Lambda Parameter");
    }
}
Comment 3 Sarika Sinha CLA 2016-04-25 03:07:39 EDT
Moving to 4.7. 
Thanks Jesper for detailed analysis.
I am not sure we want to do any assumption based on compiler implementation detail.
Comment 4 Markus Keller CLA 2016-05-04 07:36:50 EDT
(In reply to Sarika Sinha from comment #3)
> I am not sure we want to do any assumption based on compiler implementation
> detail.

We don't want to, but if there's no other choice, then we have to:
- add workarounds (with fallbacks), and properly document the unsafe assumptions 
- file an enhancement request to get the necessary APIs added to JDI

Since the OpenJDK bug tracker is effectively unusable, we should first capture our requirements in a public place like wiki.eclipse.org.
Comment 5 Sarika Sinha CLA 2017-05-17 05:53:47 EDT
Will start by creating a wiki page to capture the requirements.
Comment 6 Sarika Sinha CLA 2017-07-10 06:31:56 EDT
Created couple of requirements -

https://wiki.eclipse.org/Debug/LambdaAndJDI
Comment 7 Sarika Sinha CLA 2017-12-11 05:53:29 EST
This bug is broken into two parts Bug 516278 and Bug 516319.

*** This bug has been marked as a duplicate of bug 516278 ***