Updated pattern match documents

Brian Goetz brian.goetz at oracle.com
Fri Sep 7 20:30:16 UTC 2018

Thanks for your comments, some comments inline.

Also, please don't cross-post between amber-spec-observers and 
amber-spec-comments; use amber-spec-observers for general discussion.

> As a scala user this looks very familiar.

Familiar, but slightly different.  Language features can't be dropped 
directly from one language into another.

One area where we would like to do better than Scala here is the 
integration of patterns as first-class members of classes.  Scala's 
patterns are inherently static, and rely on some pretty ad-hoc compiler 
transformations of magic methods like unapply.  But much of that is 
farther down the road.

> 1. tail call optimizations: as pattern matching is very often associated
> with recursion it would be nice to mention any plan about it being
> supported one day (or not).

Hard to speculate on how a single feature would integrate with tail 
calls, when we don't yet have a story for how the platform will support 
tail calls.  However, the cases in which tail calls are most critical in 
pattern matching -- sequence patterns -- are not there yet, so we have 
some time.

> 2. type casing / casting on a universally quantified type variables:
> this breaks parametricity, so functional programmers would want to avoid
> it. As I understand, in such case a default branch is required, correct?
> It would then be a nice improvement over scala, which does not emit a
> warning on non-exhaustive matches in such cases.

Exhaustiveness checking is a bit messy.  For expression switches, we 
require that switches be exhaustive, which means either (a) there's a 
total pattern at the bottom, (b) it's an enum switch and all the enums 
are accounted for (in which case we generate a hidden default to detect 
enums added after compilation), or (c) its a switch on a sealed type and 
all the type choices are accounted for (same deal with a hidden default.)

For statement switches, however, we do not require them to be 
exhaustive; we're painted into a corner by existing switch semantics.  
We might at some point support some way to say "I want this switch to be 
exhaustive" to engage the type checker's help.

> 3. Support of GADT. Is there any plan to support unification in GADT
> structural decomposition? ie. would the following code be compilable,
> one day:
> sealed interface Term<T>{}
> record Zero() implements Term<Integer>;
> record Succ(Term<Integer> pred) implements Term<Integer>;
> record Pred(Term<Integer> succ) implements Term<Integer>;
> record IsZero(Term<Integer> i) implements Term<Boolean>;
> record If<T>(Term<Boolean> cond, Term<T> then, Term<T> otherwise)
> implements Term<T>;
>      static <T> T eval(Term<T> term) {
>          return switch (term) {
>              case Zero() -> 0;
>              case Succ(var pred) -> eval(pred) + 1;
>              case Pred(var succ) -> eval(succ) - 1;
>              case IsZero(var t) -> eval(t) ==0;
>              case If(var cond, var then, var otherwise) -> eval(cond) ?
> eval(then) : eval(otherwise)
>          }
>      }

I think we can get to Zero/Succ/Pred/IsZero, as we can distinguish 
between them by inspecting their dynamic type.  The current story, which 
rejects unchecked cast conversions in the applicability check, is 
probably a little too rigid, but I think we can get there, because the 
goal here its fundamentally consistent with the approach we've taken.

For If<T>, we're fine, because we know term to be a Term<T>, and it 
doesn't require an unchecked cast to get from Term<T> to If<T>.

So, I don't see this as posing any surprise challenges.

More information about the amber-spec-observers mailing list