method references: type inference, toString()
Rémi Forax
forax at univ-mlv.fr
Tue Feb 21 15:34:16 PST 2012
On 02/21/2012 11:31 PM, Paul Holser wrote:
> Hi lambda-dev,
>
> Using JDK 8 Developer Preview with lambda support
> (http://download.java.net/lambda/b25/windows-i586/lambda-8-b25-windows-i586-05_feb_2012.zip),
> Guava 11.0, Hamcrest 1.3.RC2, and JUnit 4.10 (sans Hamcrest classes).
>
> org.hamcrest.Matcher is not a SAM type, whereas
> com.google.common.base.Predicate is.
>
> Compiling Main.java:
>
> ==== begin Main.java ====
> import com.google.common.base.Predicate;
> import org.hamcrest.Description;
> import org.hamcrest.TypeSafeMatcher;
> import org.junit.Test;
>
> import static org.hamcrest.MatcherAssert.assertThat;
>
> interface Foo {
> boolean isBar();
> }
>
> abstract class PredicateMatcher<T> extends TypeSafeMatcher<T> {
> protected final Predicate<? super T> predicate;
>
> private PredicateMatcher(Predicate<? super T> predicate) {
> this.predicate = predicate;
> }
>
> @Override public final boolean matchesSafely(T target) {
> return predicate.apply(target);
> }
>
> public static<U> PredicateMatcher<U> matches(Predicate<? super U>
> predicate) {
> return new PredicateMatcher<U>(predicate) {
> @Override public void describeTo(Description description) {
> description.appendText("a value acceptable to predicate ");
> description.appendValue(this.predicate);
> }
> };
> }
> }
>
> class BarredUpFoo implements Foo {
> @Override public boolean isBar() {
> return true;
> }
> }
>
> class BarredUpFooTest {
> @Test public void bar() {
> assertThat(new BarredUpFoo(), PredicateMatcher.matches(Foo::isBar));
> }
> }
>
> public class Main {
> public static void main(String... args) {
> Predicate<Foo> bar = Foo::isBar;
> System.out.println(bar);
> }
> }
> ==== end Main.java ====
>
> yields:
>
> ==== begin console output ====
> Main.java:41: error: no suitable method found for matches(member reference)
> assertThat(new BarredUpFoo(), PredicateMatcher.matches(Foo::isBar));
> ^
> method PredicateMatcher.<U>matches(Predicate<? super U>) is not applicable
> (cyclic inference - cannot infer target type for given lambda/method refer
> ence expression)
> method TypeSafeMatcher.matches(Object) is not applicable
> (actual argument member reference cannot be converted to Object by method
> invocation conversion
> (the target type of a lambda conversion must be an interface))
> where U is a type-variable:
> U extends Object declared in method<U>matches(Predicate<? super U>)
> 1 error
> ==== end console output ====
>
> Couple of questions:
>
> 1) Should the usage of Foo::isBar as the predicate fed to
> PredicateMatcher.matches() compile successfully? I'm hoping not to
> have to perform the SAM conversion by hand:
>
> Predicate<Foo> bar = Foo::isBar;
> assertThat(new BarredUpFoo(), PredicateMatcher.matches(bar);
>
> In Main.main(), I perform that SAM conversion by hand, as you can see
> -- otherwise, it won't know to choose PrintStream.println(Object), it
> says "(actual argument member reference cannot be converted to Object
> by method invocation conversion)".
I only answer easy question, I let this one to Maurizio :)
>
> 2) Wondering if it wouldn't be too much trouble to have method
> references respond to toString() with something like "Foo::isBar" or
> "method isBar on class Foo", instead of, e.g. "Main$1 at a30a4e". It'd
> make the output of PredicateMatcher.matches() really slick.
There are two major problems.
First security, if toString() exposes declaring class and method name
you may show to much information for an attacker. Don't forget that
the class may be non public and the method private.
Second, performance, we want a VM to be able to implement the SAM
conversion as a kind of proxy around a function pointer, i.e something
that may not carry around the fat Object data structure.
One possible solution.
Because we also want lambda/method reference to be Serializable
we are discussing an opt-in mechanism that will allow lambdas to
be Serializable by having a stable name (thus a meaningful toString).
But this kind of lambda may be less thin (and perhaps less efficient).
>
> Thanks for the help, and the great work thus far!
>
> Cheers,
> Paul Holser
>
cheers,
Rémi
More information about the lambda-dev
mailing list