New JEP: Concise Method Bodies
Kevinjeet Gill
kevinjeetgill at gmail.com
Wed Oct 17 22:00:35 UTC 2018
I know I'm a little late to the party but I wanted to chime in with some
concerns. I'm sure some have come up few times.
TL;DR; For Named Classes the "=" syntax seems problematic to me while the
"->" seems harmless at best. Alex Buckley's
Anonymous Class examples highlight the best, most exciting usage and it
would be cool to double down on those.
ps - Sorry for rambling.
My feeling is that the use cases for Named Classes few and fairly narrow.
Using them for getters saves almost nothing since
you still have to go through the song and dance of "public Type getVar()"
bit. It will never live up to the "why can't we just have properties"
crowd and if we get Records even those uses will dry up.
Delegating is much more useful and comes up but as soon as we look at
anything non-trival the expressions get ambiguous as
others have mentioned. The method "=" form is especially problematic.
Consider:
(non-static) Type delegate(Type a, Type b) =
_intanceVar.getSecondDelegate()::method
I would assume this acts like the following two; calling
getSecondDelegate() every invocation:
Type delegate(Type a, Type b) ->
_intanceVar.getSecondDelegate().method(a, b)
or Type delegate(Type a, Type b) { return
_intanceVar.getSecondDelegate().method(a, b); }
Note that this is different from: var local =
_intanceVar.getSecondDelegate()::method; where it is expected to act like
var second = _intanceVar.getSecondDelegate(); var local = second::method.
Where getSecondDelegate() is called only once.
Now, maybe that assumption would be wrong! Maybe it's just a matter of
learning what it really does! This (for me) opens a
pandoras box of questions: Is _instanceVar not allowed, should it be
static? or is a final _instanceVar okay if it's initialized
before the constructor? what if is assigned in the constructor? If it's the
latter I'd assume that <init> now operates like:
> executed field initializer expressions in order, > execute constructor
code, > execute method initializers/resolve to method references now.
If getSecondDelegate() has side-effects what does that mean for:
class C {...
Type delegate1(Type a, Type b) = _intanceVar.getSecondDelegate()::method
Type delegate2(Type a, Type b) = _intanceVar.getSecondDelegate()::method
Type delegate3(Type a, Type b) = _intanceVar.getSecondDelegate()::method
...}
Method declarations have a defined program order now too? Classes used to
be a little more declarative, but reordering
methods is more fragile now. Not a *huge* deal to learn these details, but
have we really won that much? I like to think of
Java's hallmark being a language of few sharp-edges. Does this contribute
to that?
In contrast the "->" notation for concise method bodies has few if any
ambiguities. I'm still not a fan, but thats more a matter
of personal taste. I don't have any real concerns. The slight concise-ness
gain feels a bit arbitrary?
The exception is Anonymous Classes; they need work!
I want to take a second to praise the design for lambdas. They changed the
language dramatically. They opened so many doors
and solved a ton of problems incredibly well. Introducing
interface/parameter inference was make or break. Being concise is so
important especially when it's "inline" with my code and useful as an
expression. Requiring bound variables to be effectively final is both
subtle and brilliant. I didn't even realize all the problems I'd avoided
until id been caught flat footed in some language's mystical, tricky
variable/scope binding rules for closures (looking at you python).
Taking inspiration from lambdas the biggest impact Concise Method Bodies
can have is towards Anonymous Classes. Unlike
Named Classes, they are used as expressions inline with "regular" code, so
they gain a ton of value by being concise. Before lambdas,
they were much more prevalent as listeners, trace objects, plugins, state
machines, etc. so their role in API design is well proven but
they're bulky and a pain.
If we ignore their use in Named Classes and focus instead on Anonymous
Classes we can infer the Abstract Class's type as well as
return types and parameters types from a function name. Theres a ton of
cases I haven't yet fully considered around generics and
overloading, but consider something like following:
String[] tokens = string.split();
Iterator<String> iter = new {
int x = 0;
hasNext() -> (tokens.length - x) > 0;
next() -> tokens[x++] + "\n";
}
- or -
FutureCallback<String> = new {
onSuccess(v) -> _queue.addAll(v.split());
onFailure(t) -> LOG.error("RPC failed with exception: ", t);
}
(Not the most compelling examples but I couldn't think of another interface
in the JDK)
We've expanded our expressive power quite considerably and a ton of API
choices are now convenient again.
There are still questions around Interfaces Only vs Abstract. Overloaded
functions based on type and airity etc.
Sorry if this veered a little off topic.
On Tue, Oct 9, 2018 at 2:01 PM <forax at univ-mlv.fr> wrote:
> > De: "Kevin Bourrillion" <kevinb at google.com>
> > À: "Remi Forax" <forax at univ-mlv.fr>
> > Cc: "daniel smith" <daniel.smith at oracle.com>, "amber-spec-experts"
> > <amber-spec-experts at openjdk.java.net>
> > Envoyé: Mardi 9 Octobre 2018 21:39:07
> > Objet: Re: New JEP: Concise Method Bodies
>
> > On Tue, Oct 9, 2018 at 12:34 PM < [ mailto:forax at univ-mlv.fr |
> forax at univ-mlv.fr
> > ] > wrote:
>
> >>> I do like that feature, but, aren't statics the only things that are
> already
> >>> easy to make lazy (holder class)?
> >>> This pattern should already be evangelized heavily today for anyone
> with Java 8
> >>> and up.
>
> >> The holder class is a great pattern until you have a better one (sorry
> just
> >> kidding).
>
> > I hope you're not kidding because I agree with you 100%. :-)
>
> the kidding was on the word "better" because if you have some side effect,
> you clearly should not use the lazy static final.
>
> > This has become a tangent of a tangent. My only purpose was to make
> clear that
> > the value of implement-Comparable-by-delegating-to-Comparator idiom is
> already
> > here and real today as of Java 8, not something that will only become a
> good
> > pattern contingent on new features. The new features will just make it
> even, as
> > you say, better.
>
> this also remember me that if the lambda proxies are value types at
> runtime, we may not need any static field at all, because no allocation is
> really needed.
>
> Rémi
>
> >>> On Tue, Oct 9, 2018 at 11:50 AM < [ mailto:forax at univ-mlv.fr |
> forax at univ-mlv.fr
> >>> ] > wrote:
>
> >>>>> De: "Kevin Bourrillion" < [ mailto:kevinb at google.com |
> kevinb at google.com ] >
> >>>>> À: "daniel smith" < [ mailto:daniel.smith at oracle.com |
> daniel.smith at oracle.com ]
> >>>>> >
> >>>>> Cc: "Remi Forax" < [ mailto:forax at univ-mlv.fr | forax at univ-mlv.fr ]
> >,
> >>>>> "amber-spec-experts" < [ mailto:amber-spec-experts at openjdk.java.net
> |
> >>>>> amber-spec-experts at openjdk.java.net ] >
> >>>>> Envoyé: Mardi 9 Octobre 2018 20:48:10
> >>>>> Objet: Re: New JEP: Concise Method Bodies
>
> >>>>> On Tue, Oct 9, 2018 at 11:43 AM Dan Smith < [ mailto:
> daniel.smith at oracle.com |
> >>>>> daniel.smith at oracle.com ] > wrote:
>
> >>>>>> We have a rich API for building Comparators. I would expect most
> non-legacy
> >>>>>> implementations of Comparable to implement their 'compareTo' method
> by
> >>>>>> delegating to a Comparator.
>
> >>>>> +100
> >>>>> To me, this pattern is the strongest use case for the entire feature.
>
> >>>> We need the lazy static final feature too.
>
> >>>> Rémi
>
> >>> --
> >>> Kevin Bourrillion | Java Librarian | Google, Inc. | [ mailto:
> kevinb at google.com |
> >>> kevinb at google.com ]
>
> > --
> > Kevin Bourrillion | Java Librarian | Google, Inc. | [ mailto:
> kevinb at google.com |
> > kevinb at google.com ]
>
More information about the amber-spec-observers
mailing list