Is case var(var x, var y) a valid syntax ?

forax at univ-mlv.fr forax at univ-mlv.fr
Sun Sep 13 11:00:45 UTC 2020


> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "Guy Steele" <guy.steele at oracle.com>, "Alan Malloy" <amalloy at google.com>,
> "amber-spec-experts" <amber-spec-experts at 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 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200913/635357e1/attachment-0001.htm>


More information about the amber-spec-experts mailing list