> De: "Brian Goetz" <brian.go...@oracle.com> > À: "Remi Forax" <fo...@univ-mlv.fr> > Cc: "Guy Steele" <guy.ste...@oracle.com>, "Alan Malloy" <amal...@google.com>, > "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Envoyé: Mardi 8 Septembre 2020 00:52:11 > Objet: Re: Is case var(var x, var y) a valid syntax ?
>> The deconstruction pattern is a special case of type pattern > No, it isn't. I think you want it to be, but it isn't. >> , both starts by doing a typecheck (an instanceof), what is different is how >> they bind variables after the typecheck. >> So having the type inference on the type used by the typecheck working for >> the >> type pattern but not for the destruction pattern strike me as weird. > I think you may just not understand the model here. > In generality, a pattern: > - Is either total or partial. Deconstruction patterns are total; other > patterns > we'll be able to express later, such as `Optional.of(var x)`, are partial. > - Has a target type. In order for the pattern to match, the dynamic type of > the > target must be cast-convertible to this target type. > - Has a set of output bindings. Let's focus on the total pattern first, as you said a deconstruction pattern is total, it's an instanceof + a destructuring phase + a binding phase, while a type pattern is just an instanceof + a binding phase, that why a deconstruction pattern is a subset of a A declared pattern (the partial one) is an instanceof + destructurring + a where clause + a binding phase so it's not a subset of a deconstruction pattern but it's a subset of the type pattern too. > So, if the user says: > case Foo(int x): > This means: > - (static) perform overload selection on the deconstructors of Foo, and look > for > one that is compatible with the binding list `(int x)`. Compile error if there > isn't one (or are too many.) > - (dynamic) test the target to see if it is cast-convertible to Foo. If it is, > because the pattern is total (no additional match conditions), the > deconstruction pattern is going to match. Invoke the deconstructor to get the > bindings. yes, it's the same semantics of a type pattern followed by a call to the deconstructor + a binding of the variables, i believe that the problem is that you see the deconstructor as an inverse of the constructor, which is a kind of right but not fully right. >> At the same time, i understand why people can find the syntax awkward. I just >> want to be sure that it's not awkward just because it's a new syntax. > It's not the syntax, it's the concept. >> By example, with this switch, that has two cases that are semantically >> identical >> switch(point) { >> case Point p where p.x() == 0 -> ... >> case Point(var x, var _) where x == 0 -> ... > No, they are not semantically identical, except maybe for a record (because > records are so constrained.) The first is invoking a method p.x(); the second > is invoking a deconstructor, which has a binding called x. If the two happen > to > be talking about the same x, then it will come out the same, but you have no > reason to assume that just based on the spelling of `x`. They could be > describing entirely different things. The language has no business guessing > the > semantics of a method based on its name. given your example here, it doesn't work for a record too, if someone add an override method x() that return the value of y, it doesn't work. The same is true with a deconstructor, if you return for the deconstructor (int x, int y) the value of y and 0, you have exacly the same kind of issue. So there are semantically equivalent iff the accessor and the deconstructor are not correctly written. > In order to make them work out, you need a system of "properties" to guarantee > that when a deconstructor binds a `x`, and an accessor method returns an `x`, > they are guaranteed to be the same `x`. I don't blame you for wanting such a > system, but you don't get to sneak it in the back door.... you don't need properties, because for a record, you have the components which is very like properties and for the other classes, you have a mechanism to transform an instance to a record, what you call a deconstructor, so by transitivity you have a way to unbundle an instance to a set of components. >> How the deconstructors are represented in the surface language, how they are >> called or how the data values flow to the bindings are another stories for >> another time. > No, this is not a syntax problem; it is a conceptual problem. You are > asserting > that deconstructors means something different than they do. No, what i've proposed is _at runtime_ to have a different way to bind the components to the local variable to have a better backward compatibility, from the language POV, you still have a deconstructor that you call You have proposed to use a synthetic record as return value of a deconstructor, i don't like it because it means that each time you re-compile your code you may have an issue and that if you use a name generated from the set of all record component types, it doesn't work if you add a new component. I think that we can come with a better way to reference the deconstructor in the bytecode in a way that support adding a new component to a deconstructor. I may be wrong, but anyway, it has nothing to do with if a type pattern is a subtype of a deconstructor pattern or not. Rémi