Intersection types in patterns
John Rose
john.r.rose at oracle.com
Sun Oct 21 05:31:28 UTC 2018
On Oct 20, 2018, at 8:04 PM, Guy Steele <guy.steele at oracle.com> wrote:
>
>> On Oct 20, 2018, at 12:42 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
>>
>>>> case Point(var x, var y) p: ...
>>>>
>>>
>>> Is there a situation where you could have reached that case without
>>> having a reference to p? If I've understood so far:
>>>
>>> SomeSuperTypeOfPoint q;
>>>
>>> switch (q) {
>>> case Point(var x, var y) p: ... // p == q and p : Point
>>> }
>>
>> Yes, you could have gotten there via
>>
>> switch (getAnObjectForMe()) {
>> case Point(var x, var y) p:
>> }
>>
>> But, one could always refactor to
>>
>> Object o = getAnObjectForMe();
>> switch (o) {
>> case Point(var x, var y) p:
>> }
>>
>> and we’re back to the previous case.
>
> I believe that @-patterns (I’ll call them that for now) are especially useful in nested situations, where it is not convenient to do that kind of refactoring:
>
> Object o = getAnObjectForMe();
> switch (o) {
> case Line(Point(var x1, var y1) p1, Point(var x2, var y2) p2):
> // Now you have your hands on the two points as well as their x and y coordinates
> }
>
> So the question is how much that comes up in practice.
>
> But even without nesting, the original example has the benefit of having verified the type of o and made it available in p with the matched type Point.
>
> This is a very convenient idiom if you want to test x and y in order to decide which method of p to call, for example.
When working with ASTs (or sea-of-nodes neighborhoods) in a compiler,
you often want to match something and then do some extra ad hoc logic
to decide what to do with the matched parts. But in real world cases there's
often some condition where you can't complete the intended transform,
due to some corner-case constraint failure (e.g., div-by-zero, non-loaded
class) and you need to return the original AST unchanged. If I don't have
@-patterns I need to refactor my switch to capture the original node
in a temp above the switch, so that's not a direct use case for @-patterns.
But the patterns can get complex, with multiple nesting levels; this happens
routinely in compilers. Then, I might want to return a result composed from
an interior node of the pattern, wired together with some extra stuff (unrelated
leaf nodes, for example). If I want to use the workaround of a temp above the
switch, I must first refactor the single switch over a nested pattern into a
nested switch over simpler patterns. That feels like falling off a cliff.
Here's a second, more general observation about @-patterns. (Can you tell
that I like them?) If all deconstruction patterns are always only for record types,
and record types are defined as being *solely* *completely* determined from
their deconstruction parameters (their "state vector"), then the only argument
for @-patterns is a weak one: You can always recover an arbitrary interior
node of a pattern-matched object by rebuilding from the leaves. The downsides
to this are acceptable in many cases: Extra GC work, and extra verbosity
(key objection: it's error-prone). But that argument runs out of steam when
you go beyond record deconstruction.
If you fully combine object-oriented APIs with patterned deconstructors, you
must allow that an object "p" may match a pattern "foo(var x, var y)" without
any contract that "p" can be fully reconstructed from "x" and "y". After all,
"p" is an object with potential private variables and special behaviors, even
if it *also* reports a match for "foo(x,y)". So @-patterns become more useful
when patterns are generalized to true pattern queries over encapsulated
objects, rather than mere record deconstructors. When those things nest,
you need to hold onto the interior nodes of the pattern via @-patterns.
Or else, as noted above, the workaround is to unwind the nested pattern
into a nested switch of simpler patterns with associated var declarations
for the desired interior nodes. But, again, that's a sharp edge for users
who need complex nested patterns *and* ad hoc logic to visit interior nodes.
— John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20181020/90546309/attachment.html>
More information about the amber-spec-experts
mailing list