Guards -- not just for switch!

Stephen Colebourne scolebourne at joda.org
Tue Dec 5 16:55:41 UTC 2017


I have left this for a few days to try and digest it. Because,
well.... its "different" is one way of putting it.

I can see how it could work in pattern matching. It feels like
overkill there, but I don't have enough experience of pattern matching
to fairly judge it.

(BTW. Is there a design document I've missed as to why there is any
attempt to retrofit the existing switch statement rather than
effectively just deprecating it? As an observer, retrofitting seems to
be constraining the design space unnecessaily.)

Generalizing guards to constructors seems like a stretch though. Of
course design by contract has been asked for over many years, and in
theory, the JVM could make use of any limitations exposed in syntax
like this (if the JVM were extended in the future). In theory, it does
locate facts more clearly. But it doesn't prevent the method from
being compiled, nor is it likely to.

The warning here is that the assert keyword is rarely used in
practice, and yet it does something similar. A quick look at the
libraries of Guava (Precondistions) or Apache Commons Lang or
OpenGamma Strata (ArgChecker) will note that there are a number of
ways to define the validation methods, particularly around the text
and type of the error wrt null (NPE vs IAE). Some will want localized
error messages too. Surely a JDK library/class (as has previously been
suggested on core-libs) would be a better place to start / thing to
do.

The concern about being unable to trap all writes (reflection) is also
a factor in my caution. The syntax asserts something about the state
of the class, that isn't actually being enforced unless its immutable.

This isn't a rejection of the concept - its more that it gives me
cause for concern. Somehow, it feels less it will fit into Java than
some of the other things being trialled.

Stephen


On 29 November 2017 at 21:54, Brian Goetz <brian.goetz at oracle.com> wrote:
> As we've swirled around the design space on pattern matching, it seems the
> sensible place to land is to not provide explicit syntax for AND and OR
> patterns, but to support guards on case labels:
>
>     case Foo(String s)
>         where (s.length() > 0): ...
>
> In the course of a separate discussion, we realized that guards can
> profitably go in some other places, too.  Like methods/constructors:
>
>     public Range(int lo, int hi)
>         where (lo <= hi) {
>             this.lo = lo;
>             this.hi = hi;
>     }
>
> and the compiler will insert a
>
>             if (!(low <= hi))
>                 throw new
> IllegalArgumentException(String.format("Precondition lo <= hi violated;
> lo=%s, hi=%s", lo, hi);
>
> at the top of the method.  We already have throws clauses in this position,
> so putting a guard clause here isn't too weird.
>
> Hoisting preconditions into "where" clauses has several benefits:
>  - Constraints are easier to find when reading the code;
>  - Constraints can be automatically hoisted into the Javadoc as
> preconditions;
>  - More compact / pleasant way to write precondition checks, which means
> users are more likely to actually specify / check input constraints;
>  - The compiler is likely to generate a more informative exception message
> than the user would be.
>
> We can keep pulling on this string, and put these on data classes (new name:
> records) too:
>
>     record Range(int lo, int hi)
>         where (lo <= hi);
>
> and the where clause just gets lowered onto the default ctor.  (We should
> probably balk if it mentions a non-final component, as we can never find all
> the writes (reflection!), and we don't want to give users a false sense of
> confidence.)
>
> For those who asked for non-nullity support, this comes for free with
> guards:
>
>     record Foo(String s)
>         where s != null;
>
>


More information about the amber-spec-observers mailing list