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.
Maybe I'm thick, but I'm still not seeing what's bothering you here?
Can you write out an example, and point to where the gap is, and narrate
your thought process while reading the code?
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.
OK, I think I finally get where you're hung up on static patterns. There
are TWO types involved:
class MumbleWidget {
static<T> ... pattern(T t) ... nonEmptyOptional(Optional<T>
target) ...
}
The types are MumbleWidget and Optional. To find the pattern, the user
says:
case MumbleWidget.nonEmptyOptional(var x):
and your concern is that users will see "MumbleWidget.something" and say
"Oh, this must be matching a MumbleWidget", and be confused that really
it is matching an Optional?