Bug 427073 - [1.8][Quick fix] "Create method ..." doesn't show FunctionalInterface types for a lambda parameter
Summary: [1.8][Quick fix] "Create method ..." doesn't show FunctionalInterface types f...
Status: ASSIGNED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 4.4   Edit
Hardware: All All
: P3 enhancement (vote)
Target Milestone: ---   Edit
Assignee: JDT-UI-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-01-31 00:34 EST by Manoj N Palat CLA
Modified: 2014-04-22 07:14 EDT (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 Manoj N Palat CLA 2014-01-31 00:34:21 EST
interface I{
	String foo();
}
public class X {
	@SuppressWarnings("unused")
	public void bar() {
		String user = newStringFunction(() -> "Hello World");
	}
}

Use Quick Assist to provide a new function.
private String newStringFunction(Object object) is the option shown - while private String newStringFunction(I i) would be the correct one.
Comment 1 Srikanth Sankaran CLA 2014-01-31 08:26:51 EST
I think the create method assist is coming from the UI. Transferring to UI
for comment.

I think this is not feasible to implement. How would the compiler or any tool
would go from a lambda without a target type to identity potential target types
and zoom in on one type I ? 

Certain heuristics may work to some degree (visible functional interface
types at that point etc.), I don't see anything that would lead to crisp
correct, viable, useful proposals for the general problem.
Comment 2 Timo Kinnunen CLA 2014-01-31 10:55:13 EST
Starting from current compilation unit, find all interfaces with @FunctionalInterface annotation and check for compatibility, broadening search scope until found. If none found, restart matching this time all interfaces not annotated @FunctionalInterface that are functional interfaces. Note that this matching can use better heuristics than type inference from the JLS, specifically it doesn't have to fail if there are two or more ambiguous target types, it can present both and let the user pick one of them.
Comment 3 Stephan Herrmann CLA 2014-01-31 14:32:23 EST
(In reply to Timo Kinnunen from comment #2)
> Starting from current compilation unit, find all interfaces with
> @FunctionalInterface annotation and check for compatibility, broadening
> search scope until found. If none found, restart matching this time all
> interfaces not annotated @FunctionalInterface that are functional
> interfaces. Note that this matching can use better heuristics than type
> inference from the JLS, specifically it doesn't have to fail if there are
> two or more ambiguous target types, it can present both and let the user
> pick one of them.

In theory you're right, but my intuition is that this algorithm would be prohibitively expensive. Plus, we don't have any infrastructure for applying "better heuristics than type inference" ;) 

Mind you that in the general case the lambda may carry no type information at all and the function interface may be a generic method, so should we present *all* that have matching arity?

Offering interfaces with @FunctionalInterface (after some filtering) could be feasible, but start by analyzing all types in your workspace whether they are functional interfaces or not doesn't sound like a winning strategy to me.
Comment 4 Timo Kinnunen CLA 2014-01-31 17:36:56 EST
(In reply to comment #3)
> In theory you're right, but my intuition is that this algorithm would be
> prohibitively expensive. Plus, we don't have any infrastructure for applying
> "better heuristics than type inference" ;)

Well working with subtype searching has given me half a mind to just write a version that skips all the niceties and reads through the indexes for all types and doing the rest in memory. Then the querying becomes chaining method calls to a stream like allTypes.stream().filter(i -> i.isInterface()).filter(i -> i.isAnnotated(FunctionalInterface.class) || i.getAbstractMethods().size() == 1).etc().etc() and the rest is performance optimization.

There's a certain simplicity to the approach, as can be seen in the second half of the implementation of org.eclipse.jdt.internal.core.hierarchy.IndexBasedHierarchyBuilder#searchAllPossibleSubTypes

> Mind you that in the general case the lambda may carry no type information at
> all and the function interface may be a generic method, so should we present
> *all* that have matching arity?

There might not be all that many candidates after all. Supplier<T>, Consumer<V>, Function<T,V> and Runnable get reused for most things and many pre-Java 8 interfaces are specialized for some narrow use if they are functional. Hard to say what happens after Java 8 is released, maybe there's an explosion in the amount of functional interfaces and a lot more choices would be presented, but then again those are the types that you'd want to be listed in the first place.

> Offering interfaces with @FunctionalInterface (after some filtering) could be
> feasible, but start by analyzing all types in your workspace whether they are
> functional interfaces or not doesn't sound like a winning strategy to me.

It would need to use different access patterns than currently to minimize memory thrashing (and disk thrashing is straight out), that's for sure. But when the compressed JDK source code can fit in a graphics card's memory 4 times over, some indexing based query API doesn't sound to me that far-fetched any more. Figuring out these indexes and the APIs for using them would be an interesting project.
Comment 5 Srikanth Sankaran CLA 2014-01-31 17:53:42 EST
(In reply to Timo Kinnunen from comment #2)
> Starting from current compilation unit, find all interfaces with
> @FunctionalInterface annotation and check for compatibility, broadening
> search scope until found. If none found, restart matching this time all
> interfaces not annotated @FunctionalInterface that are functional
> interfaces.

I should add that my somewhat pessimistic comment#1 is based on the
current infrastructure. Inventing new infrastructure was not considered.
At the moment, code assistant relies on search indexes for many operations.
Once that path is taken, we end up with just strings for type names and
all interesting details have to be reconstructed.

Offering a dialog to the user with prefix/camel case completion support
could already be a huge improvement.
Comment 6 Markus Keller CLA 2014-04-22 07:14:00 EDT
(In reply to Timo Kinnunen from comment #4)
> There might not be all that many candidates after all. Supplier<T>,
> Consumer<V>, Function<T,V> and Runnable get reused for most things [..]

Yeah, maybe we we should just add some smartness that tries to use pre-defined @FunctionalInterfaces from one of these Java SE 8 packages:

java.lang
java.util
java.util.concurrent
java.util.function