[Python-Dev] PEP 3103: A Switch/Case Statement

Talin talin at acm.org
Wed Jun 28 07:52:52 CEST 2006

Guido van Rossum wrote:
> On 6/27/06, Ron Adam <rrr at ronadam.com> wrote:
>>So modeling the switch after dictionary dispatching more directly where
>>the switch is explicitly defined first and then used later might be good
>>both because it offers reuse in the current scope and it can easily be
>>used in code that currently uses dict style dispatching.
>>    switch name:
>>       1:
>>          ...
>>       TWO:
>>          ...
>>       'a', 'b', 'c':
>>          ...
>>       in range(5,10):
>>          ...
>>       else:
>>          ...
>>    for choice in data:
>>       do choice in name:    # best calling form I can think of.
> It looks like your proposal is to change switch into a command that
> defines a function of one parameter. Instead of the "do <expression>
> in <switch>" call you could just call the switch -- no new syntax
> needed. Your example above would be
>   for choice in data:
>     name(choice)          # 'name' is the switch's name

This parallels some of my thinking -- that we ought to somehow make the 
dict-building aspect of the switch statement explicit (which is better 
than implicit, as we all have been taught.)

My version of this is to add to Python the notion of a simple 
old-fashioned subroutine - that is, a function with no arguments and no 
additional scope, which can be referred to by name. For example:

def MyFunc( x ):
    sub case_1:

    sub case_2:

    sub case_3:

    # A direct call to the subroutine:
    do case_1

    # An indirect call
    y = case_2
    do y

    # A dispatch through a dict
    d = dict( a=case_1, b=case_2, c_case_3 )
    do d[ 'a' ]

The 'sub' keyword defines a subroutine. A subroutine is simply a block 
of bytecode with a return op at the end. When a subroutine is invoked, 
control passes to the indented code within the 'sub' clause, and 
continues to the end of the block - there is no 'fall through' to the 
next block. When the subroutine is complete, a return instruction is 
exected, and control transfers back to the original location.

Because subroutines do not define a new scope, they can freely modify 
the variables of the scope in which they are defined, just like the code 
in an 'if' or 'else' block.

One ambiguity here is what happens if you attempt to call a subroutine 
from outside of the code block in which it is defined. The easiest 
solution is to declare that this is an error - in other words, if the 
current execution scope is different than the scope in which the 
subroutine is defined, an exception is thrown.

A second possibility is to store a reference to the defining scope as 
part of the subroutine definition. So when you take a reference to 
'case_1', you are actually referring to a closure of the enclosing scope 
and the subroutine address.

This approach has a number of advantages that I can see:

   -- Completely eliminates the problems of when to freeze the dict, 
because the dict is 'frozen' explicitly (or not at all, if desired.)

   -- Completely eliminates the question of whether to support ranges in 
the switch cases. The programmer is free to invent whatever type of 
dispatch mechanism they wish. For example, instead of using a dict, they 
could use an array of subroutines, or a spanning tree / BSP tree to 
represent contiguous ranges of options.

   -- Allows for development of dispatch methods beyond the switch model 
- for example, the dictionary could be computed, transformed and 
manipulated by user code before used for dispatch.

   -- Allows for experimentation with other flow of control forms.

The primary disadvantage of this form is that the case values and the 
associated code blocks are no longer co-located, which reduces some of 
the expressive power of the switch.

Note that if you don't want to define a new keyword, an alternate syntax 
would be 'def name:' with no argument braces, indicating that this is 
not a function but a procedure.

-- Talin

More information about the Python-Dev mailing list