[Python-Dev] Switch statement
rhettinger at ewtllc.com
Mon Jun 19 21:30:28 CEST 2006
>> > But there is a definite readability improvement in that you *know*
>> > that it's always the same variable that is being compared and that no
>> > other conditions are snuck into some branches.
>> Hmm, when I saw that "arbitrary expressions" were being proposed, I took
>> that took mean that the variable would have to be repeated in the
>> switch x:
>> case x.endswith('wart'): salicylic_acid()
>> case x.endswith('roid'): preparation_h()
>> default: chicken_soup()
> That seems insane, since then it would be *just* different syntax for
> if/elif. The example looks deceptive: surely the 'switch' expression
> should allow an arbitrary expression, so the 'case' wouldn't be able
> to refer to the switch part by a name unless there was syntax (or a
> convention) for defining a name by which it could be referenced. I
> think Perl 6 is defining a very general "matching" syntax which people
> interested in this might want to study, just to see how far one can
> stretch the insanity.
I share that view 100%. Can we conclude that arbitrary expressions are
fine for the switch value but that the case values must be constants?
That would neatly dispense with some proposed hypergeneralizations and
keep the discussion focused.
>> switch x:
>> case 1: one()
>> case 2: two()
>> case 3: three()
>> default: too_many()
>> Do we require that x be hashable so that the compiler can use a lookup
> That's a good question. We could define switch/case in terms of a hash
> table created by the compiler, and then raising an exception if x is
> unhashable is fair game.
> Or we could define it in terms of successive
> '==' comparisons, and then the compiler would have to create code for
> a slow path in case x is unhashable.
Too perilous. I would not like to put us in a position of generating
duplicate code or funky new opcodes for the case suites. Also, it is
better for the user to know that __hash__ is going to be called, that
the default-clause will execute when the key in not found, and that a
KeyError would be raised if x is unhashable. This is simple,
explainable, consistent behavior. Besides, if we've agreed that the
case values are required to be constants, then there isn't much in the
way of use cases for x being unhashable.
> I don't think I'm in favor of
> always taking the default path when x is unhashable; that would cause
> some surprises if an object defines __eq__ to be equal to ints (say)
> but not __hash__.
That would be unpleasant.
> Note that we currently don't have a strong test for hashable; it's
> basically "if hash(x) doesn't raise an exception" which means that we
> would have to catch this exception (or perhaps only TypeError) in
> order to implement the slow path for the successive-comparisons
> I note that C doesn't require any particular implementation for
> switch/case; there's no rule that says the numbers must fit in an
> array of pointers or anything like that. So I would be careful before
> we define this in terms of hash tables. OTOH the hash table semantics
> don't require us to commit to a definition of hashable, which is an
> How's that for a wishy-washy answer. :-)
Perfect. Wishy-washy answers reflect an open mind and they contain the
seeds of complete agreement.
My thought is that we *should* define switching in terms of hash
tables. It builds off of existing knowledge and therefore has a near
zero learning curve. The implementation is straight-forward and there
are none of the hidden surprises that we would have with
fastpath/slowpath approaches which use different underlying magic
methods and do not guarantee order of execution.
If use cases eventually emerge for an alternative path using successive
== comparisons, then it can always be considered and added later. For
now, YAGNI (neither the functionality, nor the implementation headaches,
nor the complexity of explaining what it does under all the various cases).
More information about the Python-Dev