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;


Reply via email to