`this` in concise method bodies
Brian Goetz
brian.goetz at oracle.com
Fri Oct 12 17:15:53 UTC 2018
On 10/5/2018 7:22 PM, Dan Smith wrote:
> - It's not totally clear what we do with 'this'. Kind of seems like it
> should be treated as the first parameter to be passed, but there are
> also examples in the JEP that ignore it. And is it allowed to be
> referenced by the receiver expression?
>
> void reverse() = Collections::reverse; // invoke
> Collections.reverse(this)?
> int length(String s) = String::length; // invoke s.length()?
> void altMethod() = ThisClass::method; // invoke this.method()?
> void altMethod2() = this::method; // legal?
Drilling in on `this`:
One of the strongest motivating examples was:
static final Comparator c = ...
int compareTo(T other) = c::compare;
And in this case, we want this to wire to c.compare(this, other).
However, another strong motivating case is:
final List myList = ...
int size() = myList::size;
in which case we want this to wire to myList.size() and ignore `this`
entirely.
And, both use cases are equally desirable.
We have some precedent for resolution that involves "try both", which is
the Class::method syntax, where we'll match either an instance method or
a static method passing the receiver as the first parameter. However,
this is a little different; in that case, we were still using all the
parameters, just adapting them to paper over the somewhat accidental
static/instance divide. In this case, we want to drop the receiver when
the wired-to method doesn't want it, which is a little messier. But,
also not totally novel; when adapting a value-returning method reference
to a void-returning SAM, we are willing to drop the return value.
There are (at least) two ways we could attack this. The first involves
refining the "infer a target type from the method descriptor, and then
use that for overload selection" intuition. Just as with Class::method,
where we use the target type to do overload selection for both static
and instance methods, and fail if we find neither or both, we can do the
same thing; construct both the with-receiver and without-receiver SAM,
and fail if there is not exactly one answer.
The other approach, which also leans on an existing precedent, is to
start with the method reference; if it exact, use that to condition the
adaptation to the implied SAM. Which is slightly weaker that the first
approach, as the exactness test can be fooled by inapplicable overloads
(say, with completely wrong arity, or incompatible types.)
We already discourage overloads like:
class C {
static R x(C c, ARGS)
R x(ARGS)
}
because that will make method references C::x ambiguous. With the
approaches above, we'd also have ambiguities in cases like:
class X {
void m() = Bar::m;
}
class Bar {
static void m(X x, ARGS) { }
static void m(ARGS) { }
}
That seems somewhat unlikely, but it becomes slightly more imagineable
when you have something like:
class X implements I {
void m() = Bar::m;
}
class Bar {
static void m(I i, ARGS) { }
static void m(ARGS) { }
}
But still, it doesn't seem like we'd be overrun with these.
Summary:
- Both the capture-this and drop-this cases have important motivating
use cases
- Arbitrarily dropping one or the other would compromise the feature
- There are some possibly reasonable ways of doing overload resolution
and adaptation here, at some complexity.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20181012/cfcb8dff/attachment.html>
More information about the amber-spec-experts
mailing list