[Python-ideas] Yet Another Switch-Case Syntax Proposal

Steven D'Aprano steve at pearwood.info
Sat Apr 19 05:12:24 CEST 2014


On Sat, Apr 19, 2014 at 01:08:58AM +0200, Lucas Malor wrote:

> On 18 April 2014 17:03, Joao S. O. Bueno jsbueno-at-python.org.br |
> python-ideas-at-python.org| <0ucjz7dbjt at sneakemail.com> wrote:
> 
> > It may be just me, but I fail - in a complete manner - to see how this
> > syntax can offer any
> > improvement on current if/elif chains. It seems to differ from that
> > only by reducing
> > the explicitness, and the flexibility of the test condition that can
> > be used in any
> > of the subconditions
> >
> 
> It's more simple to use when you can use it, as switch statement in the
> other languages. And it somewhat adheres to the DRY principle: why repeat
> the subject? If I'm checking what type of tarot card I have, why should I
> repeat every time I'm trying to identify a tarot card?

I think that is a misunderstanding of the DRY principle. I'll explain 
further below, but even if the idea is to avoid writing anything twice, 
the case syntax fails. Consider your example:

switch tarot case 0:
    card = "Fool"
elcase 1:
    card = "Alan Moore"
elcase 2:
    card = "High Priestess"
<etc....>


Here, you are repeating "elcase" and "card =" each time, so you are 
still repeating yourself. We can avoid that by using the lookup table 
approach:

table = {0: "Fool", 1: "Alan Moore", 2: "High Priestess", ...}
card = table[tarot]

Now that truly is a DRY solution!

I think that your interpretation of DRY does not match the intention of 
the people who invented it. DRY is not (as I understand it) concerned 
with trivial, mechanical duplication like chained if...elif:

if tarot == 0: ...
elif tarot == 1: ...
elif tarot == 2: ...

and objecting to chained if...elif as a DRY-violation is, I believe, a 
misunderstanding of DRY.

I'm going to quote Dave Thomas, co-inventer of the DRY principle:

    Most people take DRY to mean you shouldn't duplicate code. 
    *That's not its intention.* [emphasis added] The idea 
    behind DRY is far grander than that.

    DRY says that every piece of system knowledge should have 
    one authoritative, unambiguous representation. Every piece
    of knowledge in the development of something should have a
    single representation. A system's knowledge is far broader
    than just its code. It refers to database schemas, test
    plans, the build system, even documentation.

http://www.artima.com/intv/dry.html

DRY is also known as "Single Source Of Truth", which is perhaps a better 
name, since it emphasises the fact that there is a single canonical 
source of each piece of knowlege in the system, rather than putting the 
emphasis on mere mechanical duplication. In the case of your tarot 
example, it is *not* a violation of DRY, because the various elif lines 
are not *sources* of knowledge which may contradict each other. The 
worst that will happen is that if you change the variable name "tarot" 
to something else, your code will fail with a name error. DRY is not 
about reducing the amount of mechanical edits you do when you rename a 
variable.

# Single source of truth for the name of the variable is its binding:
tarotcard = draw_card()  # was "tarot"
if tarot == 0:  # now fails
    ...

Subsequent lines merely *use* the name, they don't act as potential 
sources of knowledge which could contract each other. DRY doesn't really 
have much to say about variable names, except perhaps "don't use the 
same name (in the same namespace) for different things", so if your 
motive in introducing a switch/case statement is to DRY, I think you 
need a better motive.

One motive I'd like to see is, could a switch/case statement be used to 
automate table lookups? Two problems -- albeit mild ones -- with the 
table lookup idiom is that the table lives longer than needed, and it 
puts the table in the wrong place. This motivated Nick to suggest a 
"where" block:

card = table[tarot] where:
    table = {0: "Fool", 1: "Alan Moore", 2: "High Priestess", ...}


solving both problems at once: the table is declared only when needed, 
not before hand, and does not exist outside of the block. A third 
problem, not solved by Nick's "where", is that the table requires every 
case's value ahead of time, whether it will be needed or not. When the 
values are constants, that's not a big deal, but they might be expensive 
expressions.

Perhaps there is some way to optimize a case statement so as to avoid 
these disadvantages of the table lookup idiom. To me, that is a 
reasonable motive worth chasing. I wouldn't bother with a case statement 
unless it was more efficient than a chain of if...elif.

> @Skip Montanaro: yes, switch statement is used in C also for code
> optimization. Frankly, I think this aspect is unimportant for CPython in
> the present time.

Then I think we're not going to agree on the use or need for switch.



-- 
Steven


More information about the Python-ideas mailing list