Towards member patterns
forax at univ-mlv.fr
forax at univ-mlv.fr
Fri Jan 26 17:25:33 UTC 2024
> From: "Gavin Bierman" <gavin.bierman at oracle.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "Brian Goetz" <brian.goetz at oracle.com>, "amber-spec-experts"
> <amber-spec-experts at openjdk.java.net>
> Sent: Friday, January 26, 2024 1:36:22 PM
> Subject: Re: Towards member patterns
> Hi Remi,
>> On 26 Jan 2024, at 11:08, Remi Forax <forax at univ-mlv.fr> wrote:
>> Let's retry.
>> I think your proposal solves the cases where the type you are switching on is
>> closed (final, sealed) but not if the type is open (non-sealed).
>> Let's take an example, let suppose I've the following hierarchy
>> public sealed interface Tree {
>> static Tree none() { return None.NONE; }
>> static Tree cons(Tree tree) { return new Cons(tree); }
>> }
>> private enum None implemnts Tree { NONE }
>> private class Cons implements Tree {
>> private final Tree tree;
>> private Cons(Tree tree) { this.tree = tree; }
>> }
>> If I want to have a static method children that returns all the children of the
>> Tree, using the pattern matching I would like to write
>> static List<Tree> children(Tree tree) {
>> return switch(tree) {
>> case Tree.none() -> List.of();
>> case Tree.cons(Tree child) -> List.of(child);
>> };
>> }
>> And inside Tree, i can add the following inverse methods
>> static inverse Tree none() { if (that == Tree.NONE) __yield (); }
>> static inverse Tree cons(Tree tree) { if (that instanceof Cons cons) __yield
>> (cons.tree); }
>> As I said, it works great with a closed hierarchy, but now let suppose the
>> hierarchy is not sealed, if the hierarchy is not sealed, having static
>> factories make less sense because we do not know all the subtypes. So we have
>> public interface Tree {}
>> public enum None implemnts Tree { NONE }
>> public class Cons implements Tree {
>> private final Tree tree;
>> public Cons(Tree tree) { this.tree = tree; }
>> }
>> and in the future, someone may add
>> public class Node {
>> private final Tree, left, right;
>> public Node(Tree left, Tree right) { this.left = left; this.right = right; }
>> }
>> Because the hierarchy is open, we need to use the late binding here.
>> So i may rewrite children like this
>> static List<Tree> children(Tree tree) {
>> return switch(tree) {
>> case that.extract(List<Tree> list) -> list; // wrong syntax, it's just to convey
>> the semantics
>> };
>> }
> Already here I would disagree. I think you have missed the abstraction. You
> want all `Tree` instances to support an instance pattern member (I think of an
> instance pattern member as a *view*, which I find quite suggestive)? Then you
> need to say it, e.g.:
> public interface Tree {
> pattern Parent(List<Tree> children); // all trees can be viewed as a
> // parent with children
> }
> Now your `None` and `Cons` classes will be required to implement this instance
> pattern member, i.e.
> public enum None implements Tree { NONE
> pattern Parent(List<Tree> children) {
> children = List.of();
> }
> }
> public class Cons implements Tree {
> private final Tree tree;
> public Cons(Tree tree) { this.tree = tree; }
> pattern Parent(List<Tree> children) {
> children = List.of(tree);
> }
> }
> Then you can rewrite your `children` static method (although it is perhaps a
> little defunct):
> static List<Tree> children(Tree tree) {
> return switch(tree) {
> case Parent(List<Tree> children) -> children;
> };
> }
> The switch is exhaustive because the `Parent` view is total (by the absence of
> the `partial` modifier - maybe we'll insist on `total`, TBD).
> Now you can freely extend the hierarchy, and your `children` static method will
> work without modification:
> public class Node implements Tree {
> private final Tree left, right;
> public Node(Tree left, Tree right) { this.left = left; this.right = right; }
> pattern Parent(List<Tree> children) {
> children = List.of(left, right);
> }
> }
> (Perhaps a better implementation would be to declare a *partial* `Parent` view
> and then have `None` fail, but I leave that to your imagination. This approach
> still works.)
> Or did I misunderstand your example?
I don't think so,you got it.
What was not clear is how the compiler links the pattern Parent to the pattern method Parent(List<Tree>) inside Tree.
Thanks to the mail of Brian, the answer is either "case Tree.Parent(List<Tree> children) -> ..." or "case tree.Parent(List<Tree> children) -> ...", both will work.
> Gavin
Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20240126/5f659a90/attachment-0001.htm>
More information about the amber-spec-experts
mailing list