Open gvanrossum opened 4 years ago
Yes, in a functional language it has to raise an exception because an unmatched expression does not evaluate to a value. But since Python is statement-oriented, I do not see any problem with leaving it to just do nothing.
Moreover, Scala's compiler tries to make sure that every permissible value in a match expression matches at least one case, and you might get a compilation warning/error otherwise. In practice, however, I found that I often have to put in something like a case _ => // can never happen
or case _ => // just do nothing
. Hence, I would agree and favour a "do nothing" semantics.
This might actually be linked to the syntactic question of issue #6: if matches are meant to be exhaustive, then I find case _ =>
to make much more sense to represent the "exactly one of" semantics.
Just to be complete here: in my article I had presented an argument in favour of raising an exception that was primarily based on multiple dispatch. In languages like ML, function dispatch and pattern matching are so closely related and intertwined that it is difficult to draw a clear border. If pattern matching is used in such a context, we would probably all agree that spam(1, 2)
should either execute a function or raise a TypeError
otherwise, but never just silently do nothing if the arguments do not match the parameters.
In Python and the current discussion, however, we have a completely different case. In version 2, Python supported simple pattern matching/tuple unpacking in function arguments, but has departed since. Type annotation for parameters is very specifically not checked or enforced. I feel that extending pattern matching to functions would be counter Python's current direction and the considerations that hold for functional languages are thus simple not applicable to Python.
You have convinced me. Default do nothing is Pythonic.
A curious observation in favour of raising by default + one-off matches: out of six examples in EXAMPLES.md
three examples have raise
statement in the else
part, one probably should have it, and two others can be naturally expressed as one-off matches.
This matches my observations, it is always either 1-2 special cases, or a battery of exhaustive cases.
I have to admit that's not a bad argument. Examples 1-3 all have a raise
that basically says "no cases matched". Ex. 4 has somewhat warped flow (it uses continue
! but I'd rather not use that, and duplicate the default processing in both the inner and outer default case), and Ex. 5 translates to case _: return None
. Ex. 6. could use the one-off match (and otherwise would need case _: pass
).
Actually, after thinking more about this it seems to me we are better with not raising by default (and therefore not needing the one-off matches). The point is that this whole PEP is a pretty big addition to the language, so it would make sense to minimize possible friction. I could imagine that majority of the community may be disappointed by raising by default (even though much later they will likely want it). Also not having one-off matches will make the PEP conceptually a bit smaller and easier to grasp.
(Also for people who want more the safety there is already a section that specifies static checkers should check exhaustiveness.)
That's the main reason why I've been pushing back too. Would you mind sending a PR for our PEP? It should probably mention both "raise if no case matched" and the one-off syntax in the Rejected Ideas section.
I do think that this is a one-way-door; I don't think we can switch to raising once the code has been released. (But static checkers should feel free to insist on completeness in cases where it's checkable.)
I suppose you could introduce a 'strict' keyword later to enable this behavior.
Would you mind sending a PR for our PEP?
I can send a PR tomorrow or on weekend (unlikely today).
I am going to mark this one as 'accepted' since we have come to a conclusion.
There are two schools of thought about this:
if-elif-elif
syntax withoutelse
)I currently personally favor "do nothing" -- if people want completeness they can add a catch-all case with an
assert False
.If we end up raising, what should it raise?