some experiments with Concise Method Bodies

Aaron Scott-Boddendijk talden at
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>

> 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 [2] and stripped out some extraneous stuff. I then
> copied
> it to [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 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]
> [2]
> [3]

More information about the amber-dev mailing list