Open gvanrossum opened 4 years ago
This is quite a tough one. My first instinct is to say that tuples and lists are two entirely different beasts, but that might be because of my background in Scala.
On the one hand, one of the great strengths of Python is its open protocols, i.e. that anything with __getitem__
and __len__
methods can basically pass as a tuple or list. If we could respect this here, that would actually feel quite Pythonic—even at the expense of all cats being grey.
On the other hand, I wonder how the matching protocoll would actually look like. Say, we want to translate this:
match value:
case (x, 0, y):
...
Do we just go for something like this?
if len(value) == 3:
x = value.__getitem__(0)
if value.__getitem__(1) == 0:
y = value.__getitem__(2)
...
But then, what happens if the value in question does not have a len-field? — or a __getitem__
for that matter. What happens if value
is a dictionary, where the subsequent __getitem__
s might fail although the len
-guard in the beginning did not?
Properly checking whether a value can pass as a sequence of a given length without throwing any exceptions or causing side effects might turn out to be rather tricky. In that sense, it could be much simpler to say that (x, 0, y)
really means a tuple and nothing else.
Please read the code in patma.py. It's all there, starting with isinstance(target, collections.abc.Sequence)
.
Specifically, for either [x, 0, y]
and (x, 0, y)
I would generate exactly the same code, and it would be roughly like this:
if (isinstance(target, collections.abc.Sequence)
and len(target) == 3
and target[1] == 0):
x = target[0]
y = target[2]
I think we shouldn't allow the tuple syntax. There's no advantage (and several disadvantages) vs. the list syntax, and it leaves the door open for using them differently in the future (iterator patterns, maybe?).
That's okay. Let's be minimalist to start. It'll also remind people that this isn't quite the same as unpacking assignments.
I'd like to reopen this. From https://github.com/gvanrossum/patma/issues/58#issuecomment-640960482:
I just realized that this makes patterns like
tuple([1, 2, 3])
work naturally too.
And this is actually an argument for allowing (...)
for sequence patterns, since then we could write it as the much more satisfying tuple((1, 2, 3))
.
Is there a decision on this? I am ambivalent, I can see the argument either way.
I still think we should hold off, and that the new tuple argument is a bit weak. We could always add it later if people really want it, but we are also keeping it free for other possible meanings as well.
I don't feel very strongly one way or the other, but it feels a bit wasteful to allow them here. We already deviate significantly from unpacking assignment / del
syntax, where both forms are interchangeable.
Every time I try something it seems this keeps bugging me. For example in https://github.com/gvanrossum/patma/pull/68/files I really want to write tuples, and using sequence notation for two fields of different types just feels very wrong. And there was the "line 484" in the PEP which I looked at several times without seeing the bug.
I think the argument that we could reserve them for some other feature is also weak -- it would still confuse users (since many examples of sequence tuples do look very similar to tuples, either on the LHS or on the RHS of =
).
Can we please just do this?
Okay, I'll add this to my to-do list for the implementation.
Done! Here's the commit if you'd like to review the grammar:
I think its better to use tuple
as it is immutable or the user can explicitly tell the type of sequence pattern. Like:
match point:
case list(0, 0):
print("Origin")
case tuple(0, y):
print(f"Y={y}")
case list(x, 0):
print(f"X={x}")
case tuple(x, y):
print(f"X={x}, Y={y}")
case _:
raise ValueError("Not a point")
Sequence patterns aren't quite the same as sequence unpacking assignments (the behavior for iterators and strings is different), but nevertheless we may follow their lead and allow both
(x, y)
and[x, y]
.Or perhaps not: it may be somewhat confusing that
case (x, y)
matches any sequence, not just tuples.