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

2006-06-30 Thread Armin Rigo
Hi,

On Mon, Jun 26, 2006 at 12:23:00PM -0700, Guido van Rossum wrote:
 Feedback (also about misrepresentation of alternatives I don't favor)
 is most welcome, either to me directly or as a followup to this post.

So my 2 cents, particularly about when things are computed and ways to
control that explicitly: there was a point in time where I could say
that I liked Python because language design was not constrained by
performance issues.  Looks like it's getting a matter of the past, small
step by small step.  I'll have to get used to mentally filter out
'static' or whatever the keyword will be, liberally sprinkled in
programs I read to make them slightly faster.

Maybe I should, more constructively, propose to start a thread on the
subject of: what would be required to achieve similar effects as the
intended one at the implementation level, without strange
early-computation semantics?

I'm not talking about Psyco stuff here; there are way to do this with
reasonably-simple refactorings of global variable accesses.  I have
experimented a couple of years ago with making them more direct (just
like a lot of people did, about the faster LOAD_GLOBAL trend).  I
dropped this as it didn't make things much faster, but it had a nice
side-effect: allowing call-backs for binding changes.  This would be a
good base on top of which to make transparent, recomputed-when-changed
constant-folding of simple expressions.  Building dicts for switch and
keeping them up-to-date...  Does it make sense for me to continue
this discussion?


A bientot,

Armin.
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-29 Thread Nick Coghlan
Greg Ewing wrote:
 Nick Coghlan wrote:
 
 By 'current namespace' I really do mean locals() - the cell objects 
 themselves
 would be local variables from the point of view of the currently 
 executing code.
 
 This is wrong. Cells are *parameters* implicitly passed
 in by the calling function. They may temporarily be
 referenced from the current scope, but their home
 has to be in an outer scope, otherwise they won't
 survive between calls.

As far as I'm aware, the cell objects get kept alive by the references to them 
from the closure attribute of the inner function. The actual execution frame 
of the outer function still goes away. The cell values persist because the 
function object persists between calls - it's only the execution frame that 
gets reinitialised every time.

However, I'm now clearer on the fact that Guido's main interest is in true 
once-per-process semantics for case expressions, which changes the design 
goals I was working towards.

So I think I'll try to take a break from this discussion, and let ideas 
percolate in the back of my head for a while :)

Cheers,
Nick.

-- 
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
 http://www.boredomandlaziness.org
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-29 Thread Nick Coghlan
Eric Sumner wrote:
 Forget subroutines for a moment - the main point of the thread was the
 idea that the dispatch table was built explicitly rather than
 automatically - that instead of arguing over first-use vs.
 function-definition, we let the user decide. I'm sure that my specific
 proposal isn't the only way that this could be done.
 But anything that makes the build explicit is going to be so much more
 ugly. And I still think you're trying to solve the wrong problem.
 
 Only if the programmer has to see it.  The dispatch table need not
 include the behaviors of each of the cases; it only needs to define
 what the cases are.  In most of the use cases I've seen, switch is
 used to define behavior for different values of an enumeration.  The
 dispatch table for an enumeration can be built wherever the values for
 the enumeration are defined (such as in a module).  Programmers don't
 need to bother with making a dispatch table unless they are defining
 enumeration values themselves.

You mean something like this?:

   switch x in colours:
 case RED:
 # whatever
 case GREEN:
 # whatever
 case BLUE:
 # whatever

I think Guido's right. It doesn't solve the underlying problem because the 
compiler still has to figure out how to build a dispatch table from the 
possible values in colours to the actual bytecode offsets of the cases.

Cheers,
Nick.

-- 
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
 http://www.boredomandlaziness.org
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-29 Thread Eric Sumner
On 6/29/06, Nick Coghlan [EMAIL PROTECTED] wrote:
 You mean something like this?:

switch x in colours:
  case RED:
  # whatever
  case GREEN:
  # whatever
  case BLUE:
  # whatever

 I think Guido's right. It doesn't solve the underlying problem because the
 compiler still has to figure out how to build a dispatch table from the
 possible values in colours to the actual bytecode offsets of the cases.

To implement this, you actually need two lookup tables: one particular
to the switch that maps labels to bytecode offsets, and one in the
dispatch table to map values to labels.  The former is built when the
switch is compiled, and the latter is built wherever the dispatch
table is defined.  Each lookup is still O(1), so the whole operation
remains O(1).

It is O(n) or worse to check that all of the cases in the switch are
defined in the dispatch table, but that only has to be done once per
dispatch table/switch statement pair, and can then be stred in one or
the other (probably the dispatch table, as that will be a proper
object).

  -- Eric Sumner
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-29 Thread Fredrik Lundh
Eric Sumner wrote:

 You mean something like this?:

switch x in colours:
  case RED:
  # whatever
  case GREEN:
  # whatever
  case BLUE:
  # whatever

 I think Guido's right. It doesn't solve the underlying problem because the
 compiler still has to figure out how to build a dispatch table from the
 possible values in colours to the actual bytecode offsets of the cases.

 To implement this, you actually need two lookup tables: one particular
 to the switch that maps labels to bytecode offsets, and one in the
 dispatch table to map values to labels.  The former is built when the
 switch is compiled, and the latter is built wherever the dispatch
 table is defined.  Each lookup is still O(1), so the whole operation
 remains O(1).

what's a label ?

/F 



___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-29 Thread Eric Sumner
  You mean something like this?:
 
 switch x in colours:
   case RED:
   # whatever
   case GREEN:
   # whatever
   case BLUE:
   # whatever
 
  I think Guido's right. It doesn't solve the underlying problem because the
  compiler still has to figure out how to build a dispatch table from the
  possible values in colours to the actual bytecode offsets of the cases.
 
  To implement this, you actually need two lookup tables: one particular
  to the switch that maps labels to bytecode offsets, and one in the
  dispatch table to map values to labels.  The former is built when the
  switch is compiled, and the latter is built wherever the dispatch
  table is defined.  Each lookup is still O(1), so the whole operation
  remains O(1).

 what's a label ?

In your example, RED, GREEN, and BLUE.  colours provides a mapping
from values to labels/cases, and the switch statement provides a
mapping from labels/cases to code.  Sorry about introducing a new term
without saying anything about it.

  -- Eric Sumner
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-29 Thread Fredrik Lundh
Eric Sumner wrote:

 what's a label ?

 In your example, RED, GREEN, and BLUE.  colours provides a mapping
 from values to labels/cases, and the switch statement provides a
 mapping from labels/cases to code.  Sorry about introducing a new term
 without saying anything about it.

yeah, but what are they?  integers?  strings?  names without an associated 
value?
how do you create new labels?  where are they stored?  who keeps track of them?

/F 



___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-29 Thread Eric Sumner
 yeah, but what are they?  integers?  strings?  names without an associated 
 value?
 how do you create new labels?  where are they stored?  who keeps track of 
 them?

In this scheme, dispatch tables can be considered to be reverse-lookup
namespaces.  Where a regular namespace is used to look up a value
given its name, a dispatch table is used to look up a name given its
value.  The switch statement then lets you actually do something based
on which name is returned.

  -- Eric Sumner
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Josiah Carlson

Talin [EMAIL PROTECTED] wrote:
 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:

I don't like the idea of an embedded subrutine for a few reasons.  One
of them is because you need to define the case - sub mapping
dictionaries in each pass, you are getting no improvement in speed
(which is a motivating factor in this discussion).  Even worse, the
disconnect between case definition and dispatch makes it feel quite a
bit like a modified label/goto proposal.  The ultimate killer is that
your proposed syntax (even using def) make this construct less readable
than pretty much any if/elif/else chain I have ever seen.

 - Josiah

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Nick Coghlan
Guido van Rossum wrote:
 I think we all agree
 that side effects of case expressions is one way how we can deduce the
 compiler's behind-the-scenes tricks (even School Ib is okay with
 this). So I don't accept this as proof that Option 2 is better.

OK, I worked out a side effect free example of why I don't like option 3:

   def outer(cases=None):
   def inner(option, force_default=False):
   if cases is not None and not force_default:
   switch option:
   case in cases[0]:
   # case 0 handling
   case in cases[1]:
   # case 1 handling
   case in cases[2]:
   # case 2 handling
   # Default handling
   return inner

I believe it's reasonable to expect this to work fine - the case expressions 
don't refer to any local variables, and the subscript operations on the 
closure variable are protected by a sanity check to ensure that variable isn't 
None.

There certainly isn't anything in the code above to suggest to a reader that 
the condition attempting to guard evaluation of the switch statement might not 
do its job.

With first-time-execution jump table evaluation, there's no problem - when the 
closure variable is None, there's no way to enter the body of the if
statement, so the switch statement is never executed and the case expressions
are never evaluated. Such functions will still be storing a cell object for
the switch's jump table, but it will always be empty because the code to
populate it never gets a chance to run.

With the out of order execution involved in def-time evaluation, however, the
case expressions would always be executed, even though the inner function is 
trying to protect them with a sanity check on the value of the closure variable.

Using Option 3 semantics would mean that calling outer() given the above 
function definition will give you the rather surprising result TypeError: 
'NoneType' object is unsubscriptable, with a traceback pointing to the line 
case cases[0]: in the body of a function that hasn't been called, and that 
includes an if statement preventing that line from being reached when 'cases' 
is None.

 When it comes to the question of where do we store the result? for the
 first-execution calculation of the jump table, my proposal is a 
 hidden cell
 in the current namespace.
 
 Um, what do you mean by the current namespace? You can't mean the
 locals of the function containing the switch. There aren't always
 outer functions so I must conclude you mean the module globals. But
 I've never seen those referred to as the current namespace.

By 'current namespace' I really do mean locals() - the cell objects themselves
would be local variables from the point of view of the currently executing code.

For functions, the cell objects would be created at function definition time,
for code handled via exec-style execution, they'd be created just before 
execution of the first statement begins. In either case, the cell objects 
would already be in locals() before any bytecode gets executed.

It's only the calculation of the cell *contents* that gets deferred until
first execution of the switch statement.

 So do I understand that the switch gets re-initialized whenever a new
 function object is created? That seems a violation of the first time
 executed rule, or at least a modification (first time executed per
 defined function). Or am I misunderstanding?

I took it as a given that 'first time execution' had to be per function
and/or invocation of exec - tying caching of expressions that rely on module
globals or closure variables to code objects doesn't make any sense, because
the code object may have different globals and/or closure variables next time
it gets executed.

I may not have explained my opinion about that very well though, because the 
alternative didn't even seem to be an option.

 But if I have a code object c containing a switch statement (not
 inside a def) with a side effect in one of its cases, the side effect
 is activated each time through the following loop, IIUC:
 
  d = {}
  for i in range(10):
exec c in d

Yep. For module and class level code, the caching really only has any
speed benefit if the switch statement is inside a loop.

The rationale for doing it that way becomes clearer if you consider what would 
happen if you created a new dictionary each time through the loop:

   for i in range(10):
   d = {}
   exec c in d
   print d[result]

 I'm confused how you can first argue that tying things to the function
 definition is one of the main drawbacks of Option 3, and then proceed
 to tie Option 2 to the function definition as well. This sounds like
 by far the most convoluted specification I have seen so far. I hope
 I'm misunderstanding what you mean by namespace.

It's not the link to function definitions that I object to in Option 3, it's
the idea of evaluating the cases at function 

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

2006-06-28 Thread Fredrik Lundh
Nick Coghlan wrote:

 There certainly isn't anything in the code above to suggest to a reader that
 the condition attempting to guard evaluation of the switch statement might not
 do its job.

that's why the evaluation model used in the case statement needs to be explicit.

that applies to the once but not really approach, as well as the static = in 
global
scope approach (http://online.effbot.org/2006_06_01_archive.htm#pep-static).
there are no shortcuts here, if we want things to be easy to explain and easy to
internalize.

/F 



___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Fredrik Lundh
Guido van Rossum wrote:

 Is it unacceptable - or impractical - to break the addition of switch
 to python in two (minor version separated) steps ?

 But what's the point? We have until Python 3000 anyway.

except that we may want to reserve the necessary keywords in 2.6...

/F 



___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Guido van Rossum
Looks like this doesn't help at all when pre-computing the dispatch
dict based on named constants. So this is a no-go.

I should add that ABC had such named subroutines (but not for
switching); I dropped them to simplify things. They're not an
intrinsically undesirable or even unnecessary thing IMO. But it
doesn't solve my use case for switching. The syntax is also seriously
cumbersome compared to a PEP-3103-style switch.

--Guido

On 6/27/06, Talin [EMAIL PROTECTED] wrote:
 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' ]

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Guido van Rossum
On 6/28/06, Nick Coghlan [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  I think we all agree
  that side effects of case expressions is one way how we can deduce the
  compiler's behind-the-scenes tricks (even School Ib is okay with
  this). So I don't accept this as proof that Option 2 is better.

 OK, I worked out a side effect free example of why I don't like option 3:

def outer(cases=None):
def inner(option, force_default=False):
if cases is not None and not force_default:
switch option:
case in cases[0]:
# case 0 handling
case in cases[1]:
# case 1 handling
case in cases[2]:
# case 2 handling
# Default handling
return inner

 I believe it's reasonable to expect this to work fine - the case expressions
 don't refer to any local variables, and the subscript operations on the
 closure variable are protected by a sanity check to ensure that variable isn't
 None.

It's only reasonable if you're in school I.

As I have repeatedly said, the only use cases I care about are those
where the case expressions are constants for the lifetime of the
process. (The compiler doesn't need to know this but the programmer
does.)

 There certainly isn't anything in the code above to suggest to a reader that
 the condition attempting to guard evaluation of the switch statement might not
 do its job.

 With first-time-execution jump table evaluation, there's no problem - when the
 closure variable is None, there's no way to enter the body of the if
 statement, so the switch statement is never executed and the case expressions
 are never evaluated. Such functions will still be storing a cell object for
 the switch's jump table, but it will always be empty because the code to
 populate it never gets a chance to run.

 With the out of order execution involved in def-time evaluation, however, the
 case expressions would always be executed, even though the inner function is
 trying to protect them with a sanity check on the value of the closure 
 variable.

 Using Option 3 semantics would mean that calling outer() given the above
 function definition will give you the rather surprising result TypeError:
 'NoneType' object is unsubscriptable, with a traceback pointing to the line
 case cases[0]: in the body of a function that hasn't been called, and that
 includes an if statement preventing that line from being reached when 'cases'
 is None.

That's a perfectly reasonable outcome to me.

  When it comes to the question of where do we store the result? for the
  first-execution calculation of the jump table, my proposal is a
  hidden cell
  in the current namespace.
 
  Um, what do you mean by the current namespace? You can't mean the
  locals of the function containing the switch. There aren't always
  outer functions so I must conclude you mean the module globals. But
  I've never seen those referred to as the current namespace.

 By 'current namespace' I really do mean locals() - the cell objects themselves
 would be local variables from the point of view of the currently executing 
 code.

 For functions, the cell objects would be created at function definition time,
 for code handled via exec-style execution, they'd be created just before
 execution of the first statement begins. In either case, the cell objects
 would already be in locals() before any bytecode gets executed.

 It's only the calculation of the cell *contents* that gets deferred until
 first execution of the switch statement.

  So do I understand that the switch gets re-initialized whenever a new
  function object is created? That seems a violation of the first time
  executed rule, or at least a modification (first time executed per
  defined function). Or am I misunderstanding?

 I took it as a given that 'first time execution' had to be per function
 and/or invocation of exec - tying caching of expressions that rely on module
 globals or closure variables to code objects doesn't make any sense, because
 the code object may have different globals and/or closure variables next time
 it gets executed.

 I may not have explained my opinion about that very well though, because the
 alternative didn't even seem to be an option.

PEP 3103 discusses several ways to implement first-time-really.

I suggest that you edit the PEP to add option 2a which is
first-time-per-function-definition.

  But if I have a code object c containing a switch statement (not
  inside a def) with a side effect in one of its cases, the side effect
  is activated each time through the following loop, IIUC:
 
   d = {}
   for i in range(10):
 exec c in d

 Yep. For module and class level code, the caching really only has any
 speed benefit if the switch statement is inside a loop.

 The rationale for doing it that way becomes clearer if you consider what would
 happen if you created a new 

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

2006-06-28 Thread Josiah Carlson

Talin [EMAIL PROTECTED] wrote:
 Josiah Carlson wrote:
  Talin [EMAIL PROTECTED] wrote:
  
 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:
  
  
  I don't like the idea of an embedded subrutine for a few reasons.  One
  of them is because you need to define the case - sub mapping
  dictionaries in each pass, you are getting no improvement in speed
  (which is a motivating factor in this discussion).  Even worse, the
  disconnect between case definition and dispatch makes it feel quite a
  bit like a modified label/goto proposal.  The ultimate killer is that
  your proposed syntax (even using def) make this construct less readable
  than pretty much any if/elif/else chain I have ever seen.
  
   - Josiah
 
 The case - sub mapping doesn't need to be defined every time - that's 
 the point, you as the programmer decide when and how to construct the 
 dictionary, rather than the language trying to guess what it is you 
 want. EIBTI.

Beautiful is better than ugly.

 You could also define the switch in an outer function that contains an 
 inner function that is called multiple times:
 
 def Outer():
sub S1:
   ...
 
sub S2:
   ...
 
sub S3:
   ...
 
dispatch = {
   parser.IDENT: S1,
   parser.NUMBER: S2,
   parser.COMMENT: S3
}
 
def Inner( x ):
   do dispatch[ x ]
 
return Inner

This allows direct access to a namespace that was previously read-only
from other namespaces (right now closure namespaces are read-only,
objects within them may not be). ...


 There is also the possibility of building the dict before the function 
 is run, however this requires a method of peeking into the function body 
 and extracting the definitions there. For example, suppose the 
 subroutine names were also attributes of the function object:
 
 def MyFunc( x ):
sub upper:
   ...
sub lower:
   ...
sub control:
   ...
sub digit:
   ...
 
do dispatch[ x ]
 
 
 # Lets use an array this time, for variety
 dispatch = [
MyFunc.upper,
MyFunc.lower,
MyFunc.upper, # Yes, 2 and 3 are the same as 0 and 1
MyFunc.lower,
MyFunc.control,
MyFunc.digit,
 ]

... One of my other desires for switch/case or its equivalent is that of
encapsulation.  Offering such access from outside or inside the function
violates what Python has currently defined as its mode of operations for
encapsulation.


 With regards to your second and third points: sure, I freely admit that 
 this proposal is less readable than a switch statement. The question is, 
 however, is it more readable than what we have *now*? As I have 
 explained, comparing it to if/elif/else chains is unfair, because they 
 don't have equivalent performance. The real question is, is it more 
 readable than, say, a dictionary of references to individual functions; 
 and I think that there are a number of possible use cases where the 
 answer would be 'yes'.

Why is the comparison against if/elif/else unfair, regardless of speed? 
We've been comparing switch/case to if/elif/else from a speed
perspective certainly, stating that it must be faster (hopefully O(1)
rather than O(n)), but that hasn't been the only discussion.  In fact,
one of the reasons we are considering switch/case is because readability
still counts, and people coming from C/etc., are familliar with it. Some
find switch/case significantly easier to read, I don't, but I also don't
find it significantly harder to read.

On the other hand, if I found someone using sub in a bit of Python code,
I'd probably cry, then rewrite the thing using if/elif/else. If I was
fiesty, I'd probably do some branch counting and reorder the tests, but
I would never use subs.


 I think that language features should just work in all cases, or at 
 least all cases that are reasonable. I don't like the idea of a switch 
 statement that is hedged around with unintuitive exceptions and strange 
 corner cases.

And I don't like the idea of making my code ugly.  I would honestly
rather have no change than to have sub/def+do.

 - Josiah

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Guido van Rossum
Let's just drop the switchable subroutine proposal. It's not viable.

On 6/28/06, Josiah Carlson [EMAIL PROTECTED] wrote:

 Talin [EMAIL PROTECTED] wrote:
  Josiah Carlson wrote:
   Talin [EMAIL PROTECTED] wrote:
  
  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:
  
  
   I don't like the idea of an embedded subrutine for a few reasons.  One
   of them is because you need to define the case - sub mapping
   dictionaries in each pass, you are getting no improvement in speed
   (which is a motivating factor in this discussion).  Even worse, the
   disconnect between case definition and dispatch makes it feel quite a
   bit like a modified label/goto proposal.  The ultimate killer is that
   your proposed syntax (even using def) make this construct less readable
   than pretty much any if/elif/else chain I have ever seen.
  
- Josiah
 
  The case - sub mapping doesn't need to be defined every time - that's
  the point, you as the programmer decide when and how to construct the
  dictionary, rather than the language trying to guess what it is you
  want. EIBTI.

 Beautiful is better than ugly.

  You could also define the switch in an outer function that contains an
  inner function that is called multiple times:
 
  def Outer():
 sub S1:
...
 
 sub S2:
...
 
 sub S3:
...
 
 dispatch = {
parser.IDENT: S1,
parser.NUMBER: S2,
parser.COMMENT: S3
 }
 
 def Inner( x ):
do dispatch[ x ]
 
 return Inner

 This allows direct access to a namespace that was previously read-only
 from other namespaces (right now closure namespaces are read-only,
 objects within them may not be). ...


  There is also the possibility of building the dict before the function
  is run, however this requires a method of peeking into the function body
  and extracting the definitions there. For example, suppose the
  subroutine names were also attributes of the function object:
 
  def MyFunc( x ):
 sub upper:
...
 sub lower:
...
 sub control:
...
 sub digit:
...
 
 do dispatch[ x ]
 
 
  # Lets use an array this time, for variety
  dispatch = [
 MyFunc.upper,
 MyFunc.lower,
 MyFunc.upper, # Yes, 2 and 3 are the same as 0 and 1
 MyFunc.lower,
 MyFunc.control,
 MyFunc.digit,
  ]

 ... One of my other desires for switch/case or its equivalent is that of
 encapsulation.  Offering such access from outside or inside the function
 violates what Python has currently defined as its mode of operations for
 encapsulation.


  With regards to your second and third points: sure, I freely admit that
  this proposal is less readable than a switch statement. The question is,
  however, is it more readable than what we have *now*? As I have
  explained, comparing it to if/elif/else chains is unfair, because they
  don't have equivalent performance. The real question is, is it more
  readable than, say, a dictionary of references to individual functions;
  and I think that there are a number of possible use cases where the
  answer would be 'yes'.

 Why is the comparison against if/elif/else unfair, regardless of speed?
 We've been comparing switch/case to if/elif/else from a speed
 perspective certainly, stating that it must be faster (hopefully O(1)
 rather than O(n)), but that hasn't been the only discussion.  In fact,
 one of the reasons we are considering switch/case is because readability
 still counts, and people coming from C/etc., are familliar with it. Some
 find switch/case significantly easier to read, I don't, but I also don't
 find it significantly harder to read.

 On the other hand, if I found someone using sub in a bit of Python code,
 I'd probably cry, then rewrite the thing using if/elif/else. If I was
 fiesty, I'd probably do some branch counting and reorder the tests, but
 I would never use subs.


  I think that language features should just work in all cases, or at
  least all cases that are reasonable. I don't like the idea of a switch
  statement that is hedged around with unintuitive exceptions and strange
  corner cases.

 And I don't like the idea of making my code ugly.  I would honestly
 rather have no change than to have sub/def+do.

  - Josiah

 ___
 Python-Dev mailing list
 Python-Dev@python.org
 http://mail.python.org/mailman/listinfo/python-dev
 Unsubscribe: 
 http://mail.python.org/mailman/options/python-dev/guido%40python.org



-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org

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

2006-06-28 Thread Talin
Guido van Rossum wrote:
 Let's just drop the switchable subroutine proposal. It's not viable.
 

Perhaps not - but at the same time, when discussing new language 
features, let's not just limit ourselves to what other languages have 
done already.

Forget subroutines for a moment - the main point of the thread was the 
idea that the dispatch table was built explicitly rather than 
automatically - that instead of arguing over first-use vs. 
function-definition, we let the user decide. I'm sure that my specific 
proposal isn't the only way that this could be done.

-- Talin
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Guido van Rossum
On 6/28/06, Talin [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  Let's just drop the switchable subroutine proposal. It's not viable.

 Perhaps not - but at the same time, when discussing new language
 features, let's not just limit ourselves to what other languages have
 done already.

Well, Python 3000 is explcitly not intended as a platform for
arbitrary experimentation with feature invention (read PEP 3000).

I've gotten quite a bit of mileage out of borrowing from other
languages instead of inventing my own stuff, so I don't want to go out
inventing as a replacement of researching options that have already
been tried elsewhere.

 Forget subroutines for a moment - the main point of the thread was the
 idea that the dispatch table was built explicitly rather than
 automatically - that instead of arguing over first-use vs.
 function-definition, we let the user decide. I'm sure that my specific
 proposal isn't the only way that this could be done.

But anything that makes the build explicit is going to be so much more
ugly. And I still think you're trying to solve the wrong problem.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Eric Sumner
  Forget subroutines for a moment - the main point of the thread was the
  idea that the dispatch table was built explicitly rather than
  automatically - that instead of arguing over first-use vs.
  function-definition, we let the user decide. I'm sure that my specific
  proposal isn't the only way that this could be done.

 But anything that makes the build explicit is going to be so much more
 ugly. And I still think you're trying to solve the wrong problem.

Only if the programmer has to see it.  The dispatch table need not
include the behaviors of each of the cases; it only needs to define
what the cases are.  In most of the use cases I've seen, switch is
used to define behavior for different values of an enumeration.  The
dispatch table for an enumeration can be built wherever the values for
the enumeration are defined (such as in a module).  Programmers don't
need to bother with making a dispatch table unless they are defining
enumeration values themselves.

  -- Eric Sumner

Note: I sent an email yesterday with a proposal to this effect, but it
seems to have been lost.  If anybody wants, I can resend it.
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Greg Ewing
Nick Coghlan wrote:

 By 'current namespace' I really do mean locals() - the cell objects themselves
 would be local variables from the point of view of the currently executing 
 code.

This is wrong. Cells are *parameters* implicitly passed
in by the calling function. They may temporarily be
referenced from the current scope, but their home
has to be in an outer scope, otherwise they won't
survive between calls.

--
Greg

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-28 Thread Greg Ewing
Talin wrote:

 The case - sub mapping doesn't need to be defined every time - that's 
 the point, you as the programmer decide when and how to construct the 
 dictionary,

Then you seem to be proposing a variation on the constant-only
case option, with a more convoluted control flow.

--
Greg
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Robin Bryce
 PEP 3103, When to Freeze the Dispatch Dict/Option 1

2 things resonated with me for Raymond's proposal and the follow up:

- It seemed agnostic to almost all of the independently contentious issues.
- is defined tightly enough to allow room for growth and elaboration over
time [Raymond]. In particular it left room for
const/static/only/cached/etc to come along later.

I think its worth acknowledging this in the PEP.

Is nothing better than something in this case ? I don't know.

 I think we need a PEP for const/static/only/cached/precomputed or
 whatever people like to call it.

 Once we have (say) static, I think making the case expressions static
 by default would still cover all useful cases, and would allow us to
 diagnose duplicate cases reliably (which the if/elif chain semantics
 don't allow IIUC).

If the expectation is that static/const will evolve as a sibling pep,
does this not make Raymond's suggestion any more appealing, even a
little ?

Is it unacceptable - or impractical - to break the addition of switch
to python in two (minor version separated) steps ?

Robin
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Guido van Rossum
On 6/26/06, K.S.Sreeram [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  I think we need a PEP for const/static/only/cached/precomputed or
  whatever people like to call it.

 fredrik's got a micro pep at http://online.effbot.org

  Once we have (say) static, I think making the case expressions static
  by default would still cover all useful cases, and would allow us to
  diagnose duplicate cases reliably (which the if/elif chain semantics
  don't allow IIUC).

 Making case expressions default static would be very surprising to users
 because of the restrictions placed by static. For instance 'case in a',
 will not support containers which have a custom __contains__ method. It
 will also not support containers like lists, and sets because they are
 mutable. IMHO this doesn't feel very pythonic.

 Instead if we redefine the goal of the switch statement to be 'ease of
 expression' rather than 'optimization', then it can just be used as a
 concise alternative to if-elif chains, and we can make 'case in a' work
 with all containers where a regular 'in' statement works *AND* still
 give the possibility of fast lookup when the programmer wants, using
 explicit static.

 I feel programmer expressivity is more important, and default static
 case expressions looks like premature optimization.

You've just placed yourself in School Ia (see the updated PEP). I
respectfully disagree.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Guido van Rossum
On 6/27/06, Robin Bryce [EMAIL PROTECTED] wrote:
  PEP 3103, When to Freeze the Dispatch Dict/Option 1

 2 things resonated with me for Raymond's proposal and the follow up:

 - It seemed agnostic to almost all of the independently contentious issues.

Except for the need to use named constants.

 - is defined tightly enough to allow room for growth and elaboration over
 time [Raymond]. In particular it left room for
 const/static/only/cached/etc to come along later.

 I think its worth acknowledging this in the PEP.

Search for Raymond's name. It's there.

 Is nothing better than something in this case ? I don't know.

  I think we need a PEP for const/static/only/cached/precomputed or
  whatever people like to call it.
 
  Once we have (say) static, I think making the case expressions static
  by default would still cover all useful cases, and would allow us to
  diagnose duplicate cases reliably (which the if/elif chain semantics
  don't allow IIUC).

 If the expectation is that static/const will evolve as a sibling pep,
 does this not make Raymond's suggestion any more appealing, even a
 little ?

No, then School Ia becomes more appealing. Raymond's proposal is
unpythonic by not allowing expressions.

 Is it unacceptable - or impractical - to break the addition of switch
 to python in two (minor version separated) steps ?

But what's the point? We have until Python 3000 anyway.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Guido van Rossum
On 6/27/06, Nick Coghlan [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  I've written a new PEP, summarizing (my reaction to) the recent
  discussion on adding a switch statement. While I have my preferences,
  I'm trying to do various alternatives justice in the descriptions. The
  PEP also introduces some standard terminology that may be helpful in
  future discussions. I'm putting this in the Py3k series to gives us
  extra time to decide; it's too important to rush it.
 
http://www.python.org/dev/peps/pep-3103/

 A generally nice summary, but as one of the advocates of Option 2 when it
 comes to freezing the jump table, I'd like to see it given some better press 
 :)

Sure. Feel free to edit the PEP directly if you want.

  Feedback (also about misrepresentation of alternatives I don't favor)
  is most welcome, either to me directly or as a followup to this post.

 My preferred variant of Option 2 (calculation of the jump table on first use)
 disallows function locals in the switch cases just like Option 3. The
 rationale is that the locals can't be expected to remain the same across
 different invocations of the function, so caching an expression that depends
 on them is just as nonsensical for Option 2 as it is for Option 3 (and hence
 should trigger a Syntax Error either way).

OK, but the explanation of Option 2 becomes more cumbersome then:
instead of first time executed it now is first time executed and
you cannot use any locals (but you can use locals if you're executing
globally, and you can use locals of outer functions) (oh, and whether
locals in a class are okay is anybody's guess).

 Given that variant, my reasons for preferring Option 2 over Option 3 are:
   - the semantics are the same at module, class and function level

No they're not. At the global level, this is okay bit at the function
level it's not:

  C = 1
  switch x:
  case C: print 42

Unless I misunderstand you and you want to disallow locals at the
global level too, in which case I see this okay at the function level
but not at the global level:

  switch x:
  case re.IGNORECASE: print 42

So I don't see how this is really true.

   - the order of execution roughly matches the order of the source code

Only roughly though. One can still create obfuscated examples.

   - it does not cause any surprises when switches are inside conditional logic

 As an example of the latter kind of surprise, consider this:

def surprise(x):
   do_switch = False
   if do_switch:
   switch x:
   case sys.stderr.write(Not reachable!\n):
   pass

 Option 2 won't print anything, since the switch statement is never executed,
 so the jump table is never built. Option 3 (def-time calculation of the jump
 table), however, will print Not reachable! to stderr when the function is
 defined.

That's a pretty crooked example if you ask me. I think we all agree
that side effects of case expressions is one way how we can deduce the
compiler's behind-the-scenes tricks (even School Ib is okay with
this). So I don't accept this as proof that Option 2 is better.

 Now consider this small change, where the behaviour of Option 3 is not only
 surprising but outright undefined:

def surprise(x):
   if 0:
   switch x:
   case sys.stderr.write(Not reachable!\n):
   pass

 The optimiser is allowed to throw away the contents of an if 0: block. This
 makes no difference for Option 2 (since it never executed the case expression
 in the first place), but what happens under Option 3? Is Not reachable!
 written to stderr or not?

This is a good question. I think both behaviors are acceptable. Again,
the problem is with the side-effect-full case expression, not with
Option 3.

 When it comes to the question of where do we store the result? for the
 first-execution calculation of the jump table, my proposal is a hidden cell
 in the current namespace.

Um, what do you mean by the current namespace? You can't mean the
locals of the function containing the switch. There aren't always
outer functions so I must conclude you mean the module globals. But
I've never seen those referred to as the current namespace.

 The first time the switch statement is executed, the cell object is empty, so
 the jump table creation code is executed and the result stored in the cell. On
 subsequent executions of the switch statement, the jump table is retrieved
 directly from the cell.

OK.

 For functions, the cell objects for any switch tables would be created
 internally by the function object constructor based on the attributes of the
 code object. So the cells would be created anew each time the function
 definition is executed. These would be saved on the function object and
 inserted into the local namespace under the appropriate names before the code
 is executed (this is roughly the same thing that is done for closure
 variables). Deleting from the namespace afterwards isn't necessary, since 

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

2006-06-27 Thread Ron Adam
 Given that variant, my reasons for preferring Option 2 over Option 3 are:
   - the semantics are the same at module, class and function level
   - the order of execution roughly matches the order of the source code
   - it does not cause any surprises when switches are inside conditional logic
 
 As an example of the latter kind of surprise, consider this:
 
def surprise(x):
   do_switch = False
   if do_switch:
   switch x:
   case sys.stderr.write(Not reachable!\n):
   pass
 
 Option 2 won't print anything, since the switch statement is never executed, 
 so the jump table is never built. Option 3 (def-time calculation of the jump 
 table), however, will print Not reachable! to stderr when the function is 
 defined.

Good points on order of define vs order of execution surprises.



WARNING: probable over generalization below or really usefull idea
depending on your point of view.  ;)

I use dict base dispatching in a number of my programs and like it with
the exception I need to first define all the code in functions (or use
lambda) even if they are only one line.  So it results in a three step
process, define functions,  define dict,  and then call it.  And I need
to make sure all the function calls use the same calling signature. In
some cases I'm passing variables that one function doesn't need because
it is needed in one of the other cases.

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.


I think this avoids most of the define time/order and optimization
issues as well as the issues I have with dict base dispatching so I
thought it might be worth a mention.  There may still be some advantage
to evaluating the case expressions early, but I think it might not be
needed as much in this form so they could be evaluated at switch
definition time, which is the order the code is written.

The main arguments against this form might be that it approaches macro
and named blocks capabilities a bit too closely, but those may also be
arguments for it as this may more directly fulfill the reasons some want
named blocks and or macros.

To use a named switch in such a way just call the desired case
explicitly ...

 switch responses:
'make_red':
...
'make_blue':
...

 do 'make_red' in responses:
 ...
 do 'make_red' in responses: # again
 ...
 do 'make_blue' in responses:
 ...

So it offers local reuse of code in a more direct way than a switch
statement does and more closely matches that which is current practice
with dictionary dispatching.

Cheers,
Ron

















Just a thought,
 Ron









___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Guido van Rossum
On 6/27/06, Ron Adam [EMAIL PROTECTED] wrote:
 I use dict base dispatching in a number of my programs and like it with
 the exception I need to first define all the code in functions (or use
 lambda) even if they are only one line.  So it results in a three step
 process, define functions,  define dict,  and then call it.  And I need
 to make sure all the function calls use the same calling signature. In
 some cases I'm passing variables that one function doesn't need because
 it is needed in one of the other cases.

 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

However, early on in the switch discussion it was agreed that switch,
like if/elif, should  not create a new scope; it should just be a
control flow statement sharing the surrounding scope. The switch as
function definition would require the use of globals.

Also, it would make sense if a switch could be a method instead of a function.

I realize that by proposing a new invocation syntax (do ... in ...)
you might have intended some other kind of interaction between the
switch and the surrounding scope. but exactly what you're proposing
isn't very clear from your examples, since you don't have any example
code in the case suites, just 

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Ron Adam
Guido van Rossum wrote:
 On 6/27/06, Ron Adam [EMAIL PROTECTED] wrote:
 I use dict base dispatching in a number of my programs and like it with
 the exception I need to first define all the code in functions (or use
 lambda) even if they are only one line.  So it results in a three step
 process, define functions,  define dict,  and then call it.  And I need
 to make sure all the function calls use the same calling signature. In
 some cases I'm passing variables that one function doesn't need because
 it is needed in one of the other cases.

 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

I thought of using a function call so it would be more like using a 
generator, but also ruled it out because it does create a new scope and 
I think closures may complicate it or it would require also passing all 
the names needed for each case which would get old quick if it is 
required every time.  One of the things I want to be able to avoid in 
dict based dispatching for cases with only one or two lines of code.

So my intent was that it use the local scope and not use the function 
call signature which implies a new scope to the reader and a returned 
value, thus the 'do choice in name' calling form.  No returned value is 
needed because it has full access to local name space.

for example you wouldn't write...

return if x: 42 else: 84

but would instead...

if x:
  y = 42
else:
  y = 84
return y


The 'do' is used in the same context an 'if' is used.

switch a:
  True: y=42
  else: y=84

do x in a:
return y



 However, early on in the switch discussion it was agreed that switch,
 like if/elif, should  not create a new scope; it should just be a
 control flow statement sharing the surrounding scope. The switch as
 function definition would require the use of globals.
 
 Also, it would make sense if a switch could be a method instead of a 
 function.

There's no reason why it couldn't be put in a method.  If the switch 
uses the surrounding name space you have that flexibility.  I'm not sure 
if the select definition could be put in the body of a class and have 
the do's in a method. That would be like having an if in the body of the 
class and the else to it in a method, so I would think it wouldn't be 
allowed.  So they both would need to be in the same name space and the 
select will always need to be defined before the 'do' is executed.

 I realize that by proposing a new invocation syntax (do ... in ...)
 you might have intended some other kind of interaction between the
 switch and the surrounding scope. but exactly what you're proposing
 isn't very clear from your examples, since you don't have any example
 code in the case suites, just 

What was intended probably would be more closely related to constructing 
a switch with BASICS gosub command.


one:  # in basic these do not have their own scope
  print 'one'
  return  # return from subroutine not function here

two:
  print 'two'
  return

three:
  print 'three'
  return

data = ('one', 'two', 'three')
for choice in data:
if choice == 'one': gosub one
elif choice == 'two': gosub two
elif choice == 'three': gosub three


Which would be better expressed as..


switch choices:
'one':  print 'one'
'two':  print 'two'
'three':  print 'three'

for choice in ('one', 'two', 'three'):
do choice in choices

Each case label expression would be evaluated when the switch block is 
executed, ie... in order it appears in the program, but the code for 
each case would be skipped until a (do choice in choices) line. Each 
switch case block would not fall through but return to the next line 
after the 'do' line by default.

The whole thing could be put in a separate function or method if it's 
desired to get the single function call form you suggested along with a 
separate name space.

def switcher(choice):
switcher roo:
   1: a = 42
   42: a = 1
   else: raise ValueError

do choice in switcher:
return a

switcher(1)   -   42

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

2006-06-27 Thread Guido van Rossum
On 6/27/06, Ron Adam [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  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

 I thought of using a function call so it would be more like using a
 generator, but also ruled it out because it does create a new scope and
 I think closures may complicate it or it would require also passing all
 the names needed for each case which would get old quick if it is
 required every time.  One of the things I want to be able to avoid in
 dict based dispatching for cases with only one or two lines of code.

 So my intent was that it use the local scope and not use the function
 call signature which implies a new scope to the reader and a returned
 value, thus the 'do choice in name' calling form.  No returned value is
 needed because it has full access to local name space.

 for example you wouldn't write...

 return if x: 42 else: 84

 but would instead...

 if x:
   y = 42
 else:
   y = 84
 return y


 The 'do' is used in the same context an 'if' is used.

 switch a:
   True: y=42
   else: y=84

 do x in a:
 return y

Ah, I see.

  However, early on in the switch discussion it was agreed that switch,
  like if/elif, should  not create a new scope; it should just be a
  control flow statement sharing the surrounding scope. The switch as
  function definition would require the use of globals.
 
  Also, it would make sense if a switch could be a method instead of a
  function.

 There's no reason why it couldn't be put in a method.  If the switch
 uses the surrounding name space you have that flexibility.  I'm not sure
 if the select definition could be put in the body of a class and have
 the do's in a method. That would be like having an if in the body of the
 class and the else to it in a method, so I would think it wouldn't be
 allowed.  So they both would need to be in the same name space and the
 select will always need to be defined before the 'do' is executed.

  I realize that by proposing a new invocation syntax (do ... in ...)
  you might have intended some other kind of interaction between the
  switch and the surrounding scope. but exactly what you're proposing
  isn't very clear from your examples, since you don't have any example
  code in the case suites, just 

 What was intended probably would be more closely related to constructing
 a switch with BASICS gosub command.

I understand now.

But I have a question: if I write

  for i in range(10):
switch S:
  case i: print 42

(i.e. the switch is *inside* the for loop) does the switch get defined
10 times (with 10 different case values!) or not?

 one:  # in basic these do not have their own scope
   print 'one'
   return  # return from subroutine not function here

 two:
   print 'two'
   return

 three:
   print 'three'
   return

 data = ('one', 'two', 'three')
 for choice in data:
 if choice == 'one': gosub one
 elif choice == 'two': gosub two
 elif choice == 'three': gosub three


 Which would be better expressed as..


 switch choices:
 'one':  print 'one'
 'two':  print 'two'
 'three':  print 'three'

 for choice in ('one', 'two', 'three'):
 do choice in choices

I'm not sure I like the idea of using BASIC as a way to explain Python
functionality... :-)

 Each case label expression would be evaluated when the switch block is
 executed, ie... in order it appears in the program, but the code for
 each case would be skipped until a (do choice in choices) line. Each
 switch case block would not fall through but return to the next line
 after the 'do' line by default.

 The whole thing could be put in a separate function or method if it's
 desired to get the single function call form you suggested along with a
 separate name space.

 def switcher(choice):
 switcher roo:
1: a = 42
42: a = 1
else: raise ValueError

 do choice in switcher:
 return a

 switcher(1)   -   42
 switcher(42)  -   1
 switcher(100) -   raises exception

I'm still unclear on when you propose the case expressions to be
evaluated. Each time the switch statement is encountered? That would
be the most natural given the rest of your explanation. But then a
switch inside a function that references globally defined constants
would be re-evalulated each time the function is called; much of the
discussion here is focused on trying to reduce the number of times the
switch cases are evaluated to once per program invocation or once per
function *definition*.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)

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

2006-06-27 Thread Robin Bryce
 But what's the point? We have until Python 3000 anyway.
Ah, my mistake. In my enthusiasm, I foolishly got the time frames of
peps 3103  275 mixed up.
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Ron Adam
Guido van Rossum wrote:

 What was intended probably would be more closely related to constructing
 a switch with BASICS gosub command.
 
 I understand now.
 
 But I have a question: if I write
 
  for i in range(10):
switch S:
  case i: print 42
 
 (i.e. the switch is *inside* the for loop) does the switch get defined
 10 times (with 10 different case values!) or not?

In this instance the switch would be redefined 10 times.  The ending 
switch would be:

switch S:
   case 10: print 42


The static keyword could be used with this form as well to force define 
time evaluation. (see last example.)



 I'm not sure I like the idea of using BASIC as a way to explain Python
 functionality... :-)

Yes, I agree! :-)

Fortunately, once (and if) it's defined (what ever it turns out to be) 
Python examples can be used to explain Python.  ;-)


 Each case label expression would be evaluated when the switch block is
 executed, ie... in order it appears in the program, but the code for
 each case would be skipped until a (do choice in choices) line. Each
 switch case block would not fall through but return to the next line
 after the 'do' line by default.

 The whole thing could be put in a separate function or method if it's
 desired to get the single function call form you suggested along with a
 separate name space.

 def switcher(choice):
 switcher roo:
1: a = 42
42: a = 1
else: raise ValueError

 do choice in switcher:
 return a

 switcher(1)   -   42
 switcher(42)  -   1
 switcher(100) -   raises exception
 
 I'm still unclear on when you propose the case expressions to be
 evaluated. Each time the switch statement is encountered? That would
 be the most natural given the rest of your explanation. But then a
 switch inside a function that references globally defined constants
 would be re-evalulated each time the function is called; much of the
 discussion here is focused on trying to reduce the number of times the
 switch cases are evaluated to once per program invocation or once per
 function *definition*.

Each time the 'switch' statement is encountered for the above.


Allowing static to be used with this form could be an option to force 
function define time evaluations of cases.

 ONE = 1
 FOURTYTWO = 42

 def switcher(choice):
static switcher roo:   # evaluate cases at function def time.
   ONE: a = 42
   FOURTYTWO: a = 1
   else: raise ValueError

do choice in switcher:
   return a

 switcher(1)   -   42
 switcher(42)  -   1
 switcher(100) -   raises exception


That would give you both call time and def time evaluations for cases 
with clear behavior for both (I think).

Also since the switch has a name, it might be possible to examine their 
values with dir(switch_suite_name).  That might help in debugging and 
explaining the behavior in different situations.


The 'case' keyword could be left off in this form because the switch 
body is always a suite.  I find it more readable without it in the case 
of simple literals or named values, and more readable with it for more 
complex expressions.


I don't think I can clarify this further without getting over my head. 
  I probably am a bit already.  I'm in the know enough to get myself in 
trouble (at times) group. ;-)

Ron


___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Ron Adam
Ron Adam wrote:

 In this instance the switch would be redefined 10 times.  The ending 
 switch would be:
 
 switch S:
case 10: print 42

Silly mistake correction...  :)

   switch S:
  case 9: print 42

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-27 Thread Talin
Guido van Rossum wrote:
 On 6/27/06, Ron Adam [EMAIL PROTECTED] 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
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-26 Thread Ka-Ping Yee
On Mon, 26 Jun 2006, Guido van Rossum wrote:
 I've written a new PEP, summarizing (my reaction to) the recent
 discussion on adding a switch statement. While I have my preferences,
 I'm trying to do various alternatives justice in the descriptions.

Thanks for writing this up!

The section that most draws my attention is Semantics, and i guess
it isn't a surprise to either of us that you had the most to say
from the perspective you currently support (School II).  :)  Let me
suggest a couple of points to add:

  - School I sees trouble in the approach of pre-freezing a dispatch
dictionary because it places a new and unusual burden on the
programmer to understand exactly what kinds of case values are
allowed to be frozen and when the case values will be frozen.

  - In the School II paragraph you say Worse, the hash function
might have a bug or a side effect; if we generate code that
believes the hash, a buggy hash might generate an incorrect
match -- but that is primarily a criticism of the School II
approach, not of the School I approach as you have framed it.
It's School II that mandates that the hash be the truth.

(It looks to me like what you're actually criticizing here is
based on some assumptions about how you think School I might
be implemented, and having taken School I a number of steps
down that (unexplained) road you then see problems with it.)

Also, why is the discussion of School II mostly an argument against
School I?  What about describing the advantages of each school?


-- ?!ng
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-26 Thread Guido van Rossum
On 6/26/06, Ka-Ping Yee [EMAIL PROTECTED] wrote:
 On Mon, 26 Jun 2006, Guido van Rossum wrote:
  I've written a new PEP, summarizing (my reaction to) the recent
  discussion on adding a switch statement. While I have my preferences,
  I'm trying to do various alternatives justice in the descriptions.

 Thanks for writing this up!

 The section that most draws my attention is Semantics, and i guess
 it isn't a surprise to either of us that you had the most to say
 from the perspective you currently support (School II).  :)  Let me
 suggest a couple of points to add:

   - School I sees trouble in the approach of pre-freezing a dispatch
 dictionary because it places a new and unusual burden on the
 programmer to understand exactly what kinds of case values are
 allowed to be frozen and when the case values will be frozen.

Can you please edit the PEP yourself to add this? That will be most efficient.

   - In the School II paragraph you say Worse, the hash function
 might have a bug or a side effect; if we generate code that
 believes the hash, a buggy hash might generate an incorrect
 match -- but that is primarily a criticism of the School II
 approach, not of the School I approach as you have framed it.
 It's School II that mandates that the hash be the truth.

You seem to misunderstand what I'm saying or proposing here;
admittedly I think I left something out. With school I, if you want to
optimize using a hash table (as in PEP 275 Solution 1) you have to
catch and discard exceptions in hash(), and a bug in hash() can still
lead this optimization astray: if A == B but hash(A) != hash(B),
switch A: // case B: ... // else: ... may falsely take the else
branch, thereby causing a hard-to-debug difference between optimized
and unoptimized code. With school II, exceptions in hash() aren't
caught or discarded; a bug in hash() leads to the same behavior as
optimized school I, but the bug is not dependent on the optimization
level.

 (It looks to me like what you're actually criticizing here is
 based on some assumptions about how you think School I might
 be implemented, and having taken School I a number of steps
 down that (unexplained) road you then see problems with it.)

Right. School I appears just as keen as school II to use hashing to
optimize things, but isn't prepared to pay the price in semantics; but
I believe the optimizations are impossible to behave completely
identically to the unoptimized code (not even counting side effects in
hash() or __eq__()) so I believe the position that the optimized
version is equivalent to the unoptimized official semantics
according to school I is untenable.

 Also, why is the discussion of School II mostly an argument against
 School I?  What about describing the advantages of each school?

School II has the advantage of not incurring the problems I see with
school I, in particular catching and discarding exceptions in hash()
and differences between optimized and unoptimized code.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-26 Thread Ka-Ping Yee
On Mon, 26 Jun 2006, Guido van Rossum wrote:
 Can you please edit the PEP yourself to add this? That will be most efficient.

I've done so, and tried to clarify the next line to match (see below).

 With school I, if you want to
 optimize using a hash table (as in PEP 275 Solution 1) you have to
 catch and discard exceptions in hash(), and a bug in hash() can still
 lead this optimization astray

Right.  As written, the problem a buggy hash might generate an
incorrect match is not specific to School I; it's a problem with
any approach that is implemented by a hash lookup.  School II is
necessarily implemented this way; School I might or might not be.
So i think the part that says:

the hash function might have a bug or a side effect; if we
generate code that believes the hash, a buggy hash might
generate an incorrect match

doesn't belong there, and i'd like your consent to remove it.
On the other hand, this criticism:

if we generate code that catches errors in the hash to
fall back on an if/elif chain, we might hide genuine bugs

is indeed specific to School I + hashing.

 Right. School I appears just as keen as school II to use hashing to
 optimize things, but isn't prepared to pay the price in semantics;

Ok.  Then there's an inconsistency with the definition of School I:

School I wants to define the switch statement in term of
an equivalent if/elif chain

To clear this up, i've edited the first line of the School II
paragraph, which previously said:

School II sees nothing but trouble in that approach

It seems clear that by that approach you meant trying to achieve
if/elif semantics while using hash optimization rather than the
more general definition of School I that was given.  I believe
there are a few voices here (and i count myself among them) that
consider the semantics more important than the speed and are in
School I but aren't treating hash optimization as the quintessence
of 'switch', and we shouldn't leave them out.


-- ?!ng
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-26 Thread Guido van Rossum
On 6/26/06, Ka-Ping Yee [EMAIL PROTECTED] wrote:
 On Mon, 26 Jun 2006, Guido van Rossum wrote:
  Can you please edit the PEP yourself to add this? That will be most 
  efficient.

 I've done so, and tried to clarify the next line to match (see below).

  With school I, if you want to
  optimize using a hash table (as in PEP 275 Solution 1) you have to
  catch and discard exceptions in hash(), and a bug in hash() can still
  lead this optimization astray

 Right.  As written, the problem a buggy hash might generate an
 incorrect match is not specific to School I; it's a problem with
 any approach that is implemented by a hash lookup.  School II is
 necessarily implemented this way; School I might or might not be.
 So i think the part that says:

 the hash function might have a bug or a side effect; if we
 generate code that believes the hash, a buggy hash might
 generate an incorrect match

 doesn't belong there, and i'd like your consent to remove it.

I'd rather keep it, but clarify that school II considers the outcome
of the hash() the official semantics, while school I + dict-based
optimization would create optimized code that doesn't match the
language specs. My point being that not following your own specs is a
much more severe sin than trusting a buggy hash(). If hash() is buggy,
school II's official spec means that the bug affects the outcome, and
that's that; but because school I specifies the semantics as based on
an if/elif chain, using a buggy hash() means not following the spec.
If we choose school I, a user may assume that a buggy hash() doesn't
affect the outcome because it's defined in terms of == tests only.

 On the other hand, this criticism:

 if we generate code that catches errors in the hash to
 fall back on an if/elif chain, we might hide genuine bugs

 is indeed specific to School I + hashing.

Right.

  Right. School I appears just as keen as school II to use hashing to
  optimize things, but isn't prepared to pay the price in semantics;

 Ok.  Then there's an inconsistency with the definition of School I:

 School I wants to define the switch statement in term of
 an equivalent if/elif chain

 To clear this up, i've edited the first line of the School II
 paragraph, which previously said:

 School II sees nothing but trouble in that approach

 It seems clear that by that approach you meant trying to achieve
 if/elif semantics while using hash optimization rather than the
 more general definition of School I that was given.

Right. Thanks for the clarification; indeed, the only problem I have
with the clean school I approach (no hash-based optimization) is
that there's no optimization, and we end up once more having to tweak
the ordering of the cases based on our expectation of their frequency
(which may not match reality).

Most school I proponents (perhaps you're the only exception) have
claimed that optimization is desirable, but added that it would be
easy to add hash-based optimization. IMO it's not so easy in the light
of various failure modes of hash(). (A possible solution would be to
only use hashing if the expression's type is one of a small set of
trusted builtins, and not a subclass; we can trust int.__hash__,
str.__hash__ and a few others.)

 I believe
 there are a few voices here (and i count myself among them) that
 consider the semantics more important than the speed and are in
 School I but aren't treating hash optimization as the quintessence
 of 'switch', and we shouldn't leave them out.

This is an important distinction; thanks for pointing it out. Perhaps
we can introduce school Ia and Ib, where Ia is clean but unoptimized
and Ib is if/elif with hash-based optimization desirable when
possible.

Another distinction between the two schools is that school Ib will
have a hard time optimizing switches based on named constants. I don't
believe that the callback if variable affecting expression value is
ever assigned to approach will work.

School II is definitely more pragmatist; I really don't see much wrong
with defining that it works a certain way, which is not exactly what
you would expect but has the same effect in *most* common cases, and
then explaining odd behavior in various corner cases out of that way,
as long as I don't care about those corner cases.

This is pretty much how I defend the semantics of default parameter
values -- it doesn't matter that they are computed at function
definition time instead of call time as long as you only use immutable
constants (which could be named constants as long as they're
immutable), which is the only use case I care about.

There are many other examples of odd Python semantics that favor a
relatively simple implementation and glorify that implementation as
the official semantics. I find this much preferable over weasel words
a la traditional language standards which give optimizers a lot of
leeway at the cost of difference in behavior between different
compilers or optimization 

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

2006-06-26 Thread Ka-Ping Yee
On Mon, 26 Jun 2006, Guido van Rossum wrote:
 Most school I proponents (perhaps you're the only exception) have
 claimed that optimization is desirable, but added that it would be
 easy to add hash-based optimization. IMO it's not so easy in the light
 of various failure modes of hash(). (A possible solution would be to
 only use hashing if the expression's type is one of a small set of
 trusted builtins, and not a subclass; we can trust int.__hash__,
 str.__hash__ and a few others.)

That's a good idea!  At first glance, it seems like that could lead to
a plausible compromise.


-- ?!ng
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-26 Thread Fredrik Lundh
Guido van Rossum wrote:

 Most school I proponents (perhaps you're the only exception) have
 claimed that optimization is desirable, but added that it would be
 easy to add hash-based optimization. IMO it's not so easy in the light
 of various failure modes of hash(). (A possible solution would be to
 only use hashing if the expression's type is one of a small set of
 trusted builtins, and not a subclass; we can trust int.__hash__,
 str.__hash__ and a few others.)

that's the obvious approach for the optimize-under-the-hood school -- 
only optimize if you can do that cleanly (to enable optimization, all 
case values must be either literals or statics, have the same type, and 
belong to a set of trusted types).  this gives a speedup in all main use 
cases, and clear semantics in all cases.

another approach would be to treat switch/case and switch/case-static as 
slightly different constructs; if all cases are static, put the case 
values in a dictionary, and do the lookup as usual (propagating any errors).

/F

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2006-06-26 Thread Guido van Rossum
On 6/26/06, Fredrik Lundh [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:

  Most school I proponents (perhaps you're the only exception) have
  claimed that optimization is desirable, but added that it would be
  easy to add hash-based optimization. IMO it's not so easy in the light
  of various failure modes of hash(). (A possible solution would be to
  only use hashing if the expression's type is one of a small set of
  trusted builtins, and not a subclass; we can trust int.__hash__,
  str.__hash__ and a few others.)

 that's the obvious approach for the optimize-under-the-hood school --
 only optimize if you can do that cleanly (to enable optimization, all
 case values must be either literals or statics, have the same type, and
 belong to a set of trusted types).  this gives a speedup in all main use
 cases, and clear semantics in all cases.

 another approach would be to treat switch/case and switch/case-static as
 slightly different constructs; if all cases are static, put the case
 values in a dictionary, and do the lookup as usual (propagating any errors).

I think we need a PEP for const/static/only/cached/precomputed or
whatever people like to call it.

Once we have (say) static, I think making the case expressions static
by default would still cover all useful cases, and would allow us to
diagnose duplicate cases reliably (which the if/elif chain semantics
don't allow IIUC).

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com