[Python-Dev] switch-based programming in Python

M.-A. Lemburg mal@lemburg.com
Thu, 08 Nov 2001 16:45:07 +0100


Thomas Wouters wrote:
> 
> On Thu, Nov 08, 2001 at 12:32:39PM +0100, M.-A. Lemburg wrote:
> > Thomas Wouters wrote:
> 
> > > Would a lengthy if/elif/elif/else construct work better ?  Why ?
> 
> > Yes, because it doesn't involve calling methods, no execution
> > frames have to be setup, no arguments need to be passed in,
> > state can be managed in local variables, etc.
> 
> > > I'm not sure what you want the if/else to actually do. Personally, I
> > > either need a function call in there (in which case a dispatch table calling
> > > the function directly, sometimes with apply() or lambda-wrapper tricks, does
> > > fine) or some kind of variable assignment, in which case a simple dict
> > > lookup works just as fine. Then again, I don't write that much Python code.
> 
> > You don't ?
> 
> Is that sarcasm ? :) No, I don't. My actual job, the part I get paid for,
> doesn't (yet) involve writing Python. It's part C and Perl, part system
> design, and part administration. So Python is just a hobby.

You should change that ;-)

BTW, how did you get XS4ALL into funding the www.python.org traffic,
if they don't heavily depend on Python ?
 
> > > I personally wouldn't be adverse to a switch-like syntax, as long as we
> > > define it like a dict dispatch (the argument is evaluated once, it should be
> > > hashable, and all the 'cases' should be hashable -- preferably even
> > > compile-time constants.) I like the idea, I'm just not sure if there's
> > > enough use for it.
> 
> > That's the idea.
> 
> > There's enough need in it for my applications, so I'd go through
> > the trouble of writing the code for it, provided I get the OK
> > and help from python-dev.
> 
> The writing part would be very tricky. I don't think you can do it without
> syntax support, at least not reliably, even if 'without syntax support' is
> some kind of directive statement to signal that a particulare
> if/elif/elif/else chain should be converted to a jump table behind the
> scene.

Well, I tried to avoid syntax changes for two reasons:

1. new keywords are a problem (even though I like your proposed syntax
   very much)

2. old code should be able to benefit from the new feature

I think that Skip's proposal would go a long way (sketching here
a bit):

It should be possible for the compiler to detect an if-elif-else
construct which has the following signature:

if x == 'first':...
elif x == 'second':...
else:...

(ie. LHS always the same variable, RHS some hashable immutable
builtin type)

The compiler could then setup a perfect hash table, store it
in the constants and add some opcode which triggers the following
run-time behaviour:

At runtime, the interpreter would check x for being one of the
well-known immutable types (strings, unicode, numbers) and
use the hash table for finding the right opcode snippet.
 
> For new syntax, I'd imagine something like this:
> 
>   switch EXPR:
>   case CONSTANT:
>       [suite]
>   case CONSTANT:
>       [suite]
>   ...
>   else:
> 
> EXPR is a normal Python expression. CONSTANT should be a hashable constant
> (with a persistant hash value, duh) so we don't have to re-hash all the
> cases when entering the switch. The 'else' would function like a 'default:'
> case in C's switch. I'm not sure on the naming of 'switch' and 'case', nor
> about the indentation-level of the 'cases'. And what to do about
> fallthrough? It's commonly accepted (or at least argued :) as a design flaw
> that C's switch() defaults to fallthrough. Bytecodewise it should probably
> turn something like:

I think you missed some indents in your example. I added them again,
removing the parens around x and tweaked the formatting a bit (also
note the addition of a few breaks).
 
   def whatis(x):
       switch x:
           case 'one': 
               print '1'
               break
           case 'two':
               print '2'
               # fall through
           case 'three':
               print '3'
               break
           else: 
               print "D'oh!"

Turns out that this look very Pythonic :-)

> Into (ommitting POP_TOP's and SET_LINENO's):
> 
>    6  LOAD_FAST         0 (x)
>    9  LOAD_CONST        1 (switch-table-1)
>   12  SWITCH            26 (to 38) # or maybe 'SWITCH <table-index>'
> 
>   14  LOAD_CONST        2 ('1')
>   17  PRINT_ITEM
>   18  PRINT_NEWLINE
>   19  JUMP 43
> 
>   22  LOAD_CONST        3 ('2')
>   25  PRINT_ITEM
>   26  PRINT_NEWLINE
>   27  JUMP 43
> 
>   30  LOAD_CONST        4 ('3')
>   33  PRINT_ITEM
>   34  PRINT_NEWLINE
>   35  JUMP 43
> 
>   38  LOAD_CONST        5 ("D'oh!")
>   41  PRINT_ITEM
>   42  PRINT_NEWLINE
> 
> >>43  LOAD_CONST        0 (None)
>   46  RETURN_VALUE
> 
> Where the 'SWITCH' opcode would jump to 14, 22, 30 or 38 depending on 'x'.
> PEP, anyone ? :)

Sure smells like PEP-time :-)

If I get some more positive feedback on this, I'll start 
looking into this.

-- 
Marc-Andre Lemburg
CEO eGenix.com Software GmbH
______________________________________________________________________
Consulting & Company:                           http://www.egenix.com/
Python Software:                        http://www.lemburg.com/python/