Guards -- not just for switch!

Brian Goetz brian.goetz at oracle.com
Wed Nov 29 21:54:03 UTC 2017


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-experts mailing list