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