[External] : Re: The good and the bad static pattern ?

forax at univ-mlv.fr forax at univ-mlv.fr
Thu Jan 21 16:13:25 UTC 2021


> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Mardi 19 Janvier 2021 19:17:41
> Objet: Re: [External] : Re: The good and the bad static pattern ?

>>> Remi, is your discomfort about static patterns basically "Well, Scala gets away
>>> with having only one kind, that subsumes deconstruction and static, isn't that
>>> good enough?"
>> Not exactly, it's more than if a static pattern that reference a static method,
>> the type of the first parameter is not visible for a user.

> OK, so it is the "target to argument shifting" that is weird to you? That when
> we declare a static pattern, there is a special first argument that is the
> target ?
The sementics implies an instanceof on something which is not not visible in the syntax. 
People, me including, will have hard time to debug that, why this pattern is not chosen, oh, it's because of the instanceof. 

>> Let my try to explain in a simple way.

>> when we write
>> Object o = ...
>> switch(o) {
>> case Bar$$foo(3, var value) -> ...
>> }

> Let's not allow ourselves to be distracted by input arguments yet. (I understand
> this adds challenges but if we're having trouble getting a shared understanding
> the base case, let's not jump to the general case yet.) So I will rewrite your
> example as:

> Object o = ...
> switch (o) {
> case Bar$$foo(var value) -> ...
> }

> There are a series of things going on here that the user must understand, in
> order to understand this code.

> 1. Overload resolution. The pattern Bar$$foo(var value) corresponds to a pattern
> actually declared in some code somewhere. The user has to be able to reason as
> to how this pattern maps to this declared member. This is not all that
> different from methods; when we see `foo(x)` we have to figure out whether this
> is really `this.foo(x)` in the current class, a static foo(x), a
> static-imported method foo(x), etc. I don't think it's any harder for patterns,
> just a little different. The user should be able to navigate to / find the
> Javadoc for Bar$$foo.

> 2. When we look at the declaration for Bar$$foo, we're going to see that it
> takes one argument and has one binding. We're going to have to understand that
> the switch target is magically piped into that argument. (For dtor/instance
> patterns, the same is true, it is just magically piped to the receiver, which
> is an invisible first argument.)

> 3. If the target type of the pattern (the type of the target parameter) is not
> total on the static type of the target (Object), the compiler introduces a
> dynamic type test before invoking the pattern body, and if this type test
> fails, the match fails and we move on to the next case. This is true for all
> kinds of patterns, not just static ones; the difference is how we determine the
> type of the target.

> Which of these seem problematic to you? (Note that none of the above are
> specific to static patterns, but all are affected by static-ness vs
> instance-ness, in that we have a different way to declare and find the target
> type from a static pattern.)

>> Here, I've no idea if foo takes a String, an Integer or whatever as first
>> parameter, so i've no idea on which class the instanceof is done.

> It seems that it is #2 that is disturbing? How is "look at the declaration or
> Javadoc of the pattern" (just like any other API point) not a good answer here?
Each step is reasonable but 2 + 3 is dangerous in the case the pattern references a static pattern doesn't take the current class as first parameter. 
Optional$$of() is ok given that it can be either an instance pattern or a static pattern but in both case, the type used by instanceof is visible. 

Apart disabling the declaration of a static pattern which doesn't take the class that declares the pattern as first parameter, 
the other solution i see is to not do an instanceof if the first parameter of a static pattern is different from the class that declares it. 

i.e. Foo$$bar is either an instance pattern bar() inside Foo, a static pattern bar(Foo) inside Foo or a static pattern bar(Zorg) with Zorg a supertype of the type of the object we are switching on. 

In that case, this code compiles 
String s = ... 
switch(s) { 
case Integer$$parseInt(var value) -> 
} 
and calls Integer.parseInt(String)[int] 

But this one do not 
Object o = ... 
switch(o) { 
case Integer$$parseInt(var value) -> 
} 
because there is neither a pattern Integer.parseInt(Integer)[int] nor a pattern Integer.parseInt(Object)[int]. 

Rémi 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210121/d5f5bc73/attachment.htm>


More information about the amber-spec-experts mailing list