[Python-Dev] PEP 3103: A Switch/Case Statement
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:
>> 'a', 'b', 'c':
>> in range(5,10):
>> 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 ):
# A direct call to the subroutine:
# An indirect call
y = case_2
# 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.
More information about the Python-Dev