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