some experiments with Concise Method Bodies
Aaron Scott-Boddendijk
talden at gmail.com
Mon Oct 15 19:32:09 UTC 2018
> public boolean add(E e) -> throw new UnsupportedOperationException();
This is similar to issues with flow-control. It would be nice to be able
to do..
final Result r = condition ? goodPath() : throw new BadStuffException();
...
instead of...
final Result;
if (condition) {
result = goodPath();
} else {
throw new BadStuffException();
}
...
Either branch of the ternary should be allowed to be a throw and, if both
are throws the ternary is a Void expression (allowing for a concise 'which
exception are we throwing').
--
Aaron Scott-Boddendijk
On Tue, Oct 16, 2018 at 7:40 AM Stuart Marks <stuart.marks at oracle.com>
wrote:
> When I first saw the CMB proposal, I immediately thought "delegation" and
> so I
> thought it would be useful to see how CMB could be applied in this area.
> The
> example I chose was the implementation class for
> Collections.unmodifiableCollection(), which returns an instance of a
> wrapper
> class [1] that delegates most (but not all) method calls to the backing
> collection.
>
> I cloned the amber repo and updated to the concise-method-declarations
> branch.
> Building the JDK from this branch worked smoothly. Compiling "Hello,
> world" worked:
>
> public class Concise {
> public static void main(String[] args)
> -> System.out.println("Hello, concise method bodies!");
> }
>
> I took Collections$UnmodifiableCollection and extracted it into a
> standalone
> class UnmodColl1.java [2] and stripped out some extraneous stuff. I then
> copied
> it to UnmodColl2.java [3] and converted it to use CMB. Along the way I
> made some
> shortening transformations that didn't directly relate to CMB, so I
> retrofitted
> them back to UnmodColl1.java. The results are more-or-less diff-able.
>
> Observations:
>
> * I was able to use CMB for almost everything. These wrapper classes
> consistent
> almost entirely of one-liners, to which CMB can be directly applied.
>
> * The CMB version is a bit prettier. Lack of 'return' and braces reduces
> visual
> clutter, and in a few cases it enabled things to be moved onto a single
> line,
> reducing vertical space.
>
> * Note that these wrapper classes already bend the usual style rules for
> braces
> and statements of a method body, e.g., even in the original we have the
> method
>
> public int size() {return c.size();}
>
> written on a single line. If the style were followed strictly, this would
> be
> written on three lines. There's a reason for this; writing all these
> one-liners
> in standard style would waste an egregious amount of vertical space. CMB
> syntax
> provides a much bigger win over standard style than over the non-standard,
> compact style used in these Collections wrapper classes.
>
> On the other hand, while the non-standard, compact style does save
> vertical
> space, it's kind of annoying to deal with, because it's non-standard. In
> my
> opinion the tradeoff is in favor of the compact style. But CMB mostly
> relieves
> us of having to make this tradeoff at all.
>
> * None of these methods have javadoc, since this is a private
> implementation class.
>
> * Many of the delegating methods can be written using the method reference
> form:
>
> public int size() = c::size;
>
> This would produce a marginal improvement in the syntax, mostly by
> removing the
> need for a set of parens and the need to pass parameters explicitly. The
> issue
> of time-of-evaluation of the receiver mostly doesn't arise here, since the
> delegate is a final field initialized by the constructor.
>
> * I tried to use CMB for the constructor, but I got an error message
> saying it
> was disallowed. No great loss, and makes some sense, I guess.
>
> * Many of the methods throw exceptions. I had a bit of a wrestling match
> with
> this. My first attempt was
>
> UnsupportedOperationException uoe() -> new
> UnsupportedOperationException;
> public boolean add(E e) -> throw uoe();
>
> But this doesn't work, because 'throw' isn't an expression, and the
> concise body
> is required to be an expression of the right type even though we know the
> method
> can never return normally. Of course, one can do this:
>
> public boolean add(E e) { throw uoe(); }
>
> but I wanted to use CMB. My next attempt was this:
>
> boolean throwUOE() { throw new UnsupportedOperationException(); }
> public boolean add(E e) -> throwUOE();
>
> Now this works, but it's a hack. Most of the throwing methods happen to
> return
> boolean, so I was able to declare the helper method to return boolean as
> well.
> It can also be used for void-returning methods. But if I had needed to
> delegate
> several throwing methods that had different return types, I wouldn't be
> able to
> do this.
>
> I tried to use the method reference form to deal with the throwing
> methods, but
> that didn't work, since those methods all take different parameters.
>
> It would be nice if I could just do
>
> public boolean add(E e) -> throw new UnsupportedOperationException();
>
> or
>
> public boolean add(E e) -> throw uoe();
>
> where uoe() returns an exception instance.
>
> **
>
> Summary: it was fun playing with this feature. It seems to clean things up
> a
> little bit, and for classes that are all one-liner methods the little
> savings
> add up to a lot. The savings are incrementally greater compared to a
> hypothetical wrapper class that uses the standard coding style. CMB
> doesn't seem
> to be a must-have feature, at least not yet, but it does seem to have some
> potential.
>
> s'marks
>
>
> [1]
>
> http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/util/Collections.java#l1021
>
> [2] http://cr.openjdk.java.net/~smarks/amber/UnmodColl1.java
>
> [3] http://cr.openjdk.java.net/~smarks/amber/UnmodColl2.java
>
>
More information about the amber-dev
mailing list