Re: [Python-Dev] switch statement

2018-09-29 Thread Steven D'Aprano
On Fri, Sep 21, 2018 at 02:10:00PM -0700, Guido van Rossum wrote:
> There's already a rejected PEP about a switch statement:
> https://www.python.org/dev/peps/pep-3103/. There's no point bringing this
> up again unless you have a new use case.
> 
> There have been several promising posts to python-ideas about the much more
> powerful idea of a "match" statement. Please search for those before
> re-posting on python-ideas.

The Coconut transpiler also includes some interesting ideas for a match 
and case statement:

http://coconut-lang.org/

https://coconut.readthedocs.io/en/master/DOCS.html#match
https://coconut.readthedocs.io/en/master/DOCS.html#case


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


Re: [Python-Dev] switch statement

2018-09-21 Thread Ivan Levkivskyi
> There have been several promising posts to python-ideas about the much
more powerful idea of a "match" statement

I actually even started working on a PEP about this (pattern matching), but
then decided to postpone it because it is unlikely that anything of this
size can be discussed/accepted in current situation.
We can return back to the idea when decision-making model will clarify.

--
Ivan



On Fri, 21 Sep 2018 at 22:12, Guido van Rossum  wrote:

> There's already a rejected PEP about a switch statement:
> https://www.python.org/dev/peps/pep-3103/. There's no point bringing this
> up again unless you have a new use case.
>
> There have been several promising posts to python-ideas about the much
> more powerful idea of a "match" statement. Please search for those before
> re-posting on python-ideas.
>
> --
> --Guido van Rossum (python.org/~guido)
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/levkivskyi%40gmail.com
>
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] switch statement

2018-09-21 Thread Guido van Rossum
There's already a rejected PEP about a switch statement:
https://www.python.org/dev/peps/pep-3103/. There's no point bringing this
up again unless you have a new use case.

There have been several promising posts to python-ideas about the much more
powerful idea of a "match" statement. Please search for those before
re-posting on python-ideas.

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


Re: [Python-Dev] switch statement

2018-09-21 Thread Jonathan Goble
As Michael said, this belongs on python-ideas, but it's interesting. I'd
support it, though my input in that regard is worth approximately $0.00. ;)
It's the core devs and especially the eventual BDFL replacement whom you
would have to convince.

Without getting into an extended discussion here on python-dev, I'd like to
offer one brief comment to try to help improve the proposal:

On Fri, Sep 21, 2018 at 2:17 PM  wrote:

> Let allow fallthrough or not? - To be decided. (Either is compatible with
> the above.)
>

I would argue for non-fallthrough as the default with support for
explicitly requesting fallthrough when desired by using "continue". I don't
know of any prior art for doing it that way, but it makes sense to me. It
eliminates hidden bugs from missing a "break" while still allowing it when
needed.

Good luck with the proposal!
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] switch statement

2018-09-21 Thread Michael Selik
First, this sounds like it belongs on python-ideas, not python-dev.
Second, when you do send a message to python-ideas, it'll help to
accompany it with a realistic example usage that motivates your
proposal.
On Fri, Sep 21, 2018 at 11:18 AM  wrote:
>
> Hi,
>
> A humble proposal for a switch-like statement syntax for Python:
>
> - - -
> switch blah in (100, 2, 30, 'bumm'):
>   dosomething1()
>   x = 88
> case blah in (44, 55):
>   otherstuff(9)
> case blah in (8):
>   boo()
> else:
>   wawa()
> - - -
>
> So, let's use, and allow only *tuples*.
> As early as possible, build a jump table, based on (foreknown) small integer 
> values. As in other languages.
> Strings may have to be hashed (in "compile time"), to obtain small integer 
> value. Some secondary checking may
> have to be done for exact content equality. (Alternative: do no allow strings 
> at all.)
> For gaps in the integer range: maybe apply some very basic dividing/shifting 
> to "compact" the range. (As
> compilers optimize in other languages, I guess -- but I may be totally 
> wrong.) (For example find "unused bits"
> in the numbers (in 2-base representation). newnum = orignum >> 3 & 6 | 
> orignum & ~6. newnum is smaller (roughly
> 1/8) than orignum.)
> The (achievable) goal is to be faster than hash table lookup. (A hash table 
> with keys 100, 2, 30, 'bumm' etc.)
> And approach the speed of single array-index lookup. (Or even faster in some 
> cases as there will be just jumps
> instead of calls?)
> (I am not an "expert"!)
>
> Let allow fallthrough or not? - To be decided. (Either is compatible with the 
> above.)
>
>
> I know about PEP 3103 and
> https://docs.python.org/3.8/faq/design.html?highlight=switch#why-isn-t-there-a-switch-or-case-statement-in-python
>
> (I do not know how to comment on a PEP, where to discuss a PEP. If this is 
> inappropriate place, please forward it.)
>
> --
>
>
>
>
>
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: 
> https://mail.python.org/mailman/options/python-dev/mike%40selik.org
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] switch statement

2018-09-21 Thread e2qb2a44f
Hi,

A humble proposal for a switch-like statement syntax for Python:

- - -
switch blah in (100, 2, 30, 'bumm'):
  dosomething1()
  x = 88
case blah in (44, 55):
  otherstuff(9)
case blah in (8):
  boo()
else:
  wawa()
- - -

So, let's use, and allow only *tuples*.
As early as possible, build a jump table, based on (foreknown) small integer 
values. As in other languages.
Strings may have to be hashed (in "compile time"), to obtain small integer 
value. Some secondary checking may
have to be done for exact content equality. (Alternative: do no allow strings 
at all.)
For gaps in the integer range: maybe apply some very basic dividing/shifting to 
"compact" the range. (As
compilers optimize in other languages, I guess -- but I may be totally wrong.) 
(For example find "unused bits"
in the numbers (in 2-base representation). newnum = orignum >> 3 & 6 | orignum 
& ~6. newnum is smaller (roughly
1/8) than orignum.)
The (achievable) goal is to be faster than hash table lookup. (A hash table 
with keys 100, 2, 30, 'bumm' etc.)
And approach the speed of single array-index lookup. (Or even faster in some 
cases as there will be just jumps
instead of calls?)
(I am not an "expert"!)

Let allow fallthrough or not? - To be decided. (Either is compatible with the 
above.)


I know about PEP 3103 and
https://docs.python.org/3.8/faq/design.html?highlight=switch#why-isn-t-there-a-switch-or-case-statement-in-python

(I do not know how to comment on a PEP, where to discuss a PEP. If this is 
inappropriate place, please forward it.)

-- 





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


Re: [Python-Dev] Switch statement - handling errors

2006-06-27 Thread Jim Jewett
On 6/26/06, Guido van Rossum [EMAIL PROTECTED] wrote:
 I like Python's rules to be simple, and I
 prefer to occasionally close off a potential optimization path in the
 sake of simplicity.

(Almost) everyone agrees that the case expressions SHOULD be run-time
constants.  The disagreements are largely over what to do when this
gets violated.


Bad Case Option (1) -- Accept everything


Readability is everything.  Switch/case tells you that every branch is
using similar predicates on the same variable.  If that variable or
predicate can't be easily optimized, then so what -- it is still
better to read.  (Largely School Ia)


Bad Case Option (2) -- Accept very little
-

Enforce good case expressions.  (Raymond's proposal)  This does the
right thing when it works, but it is initially very restricted -- and
a crippled case statement may be worse than none at all.


Bad Case Option (3) -- Raise Exceptions
---

Flag bugs early.  The semantics require non-overlapping hashable
constants, so raise an exception if this gets violated.  This does the
right thing, but catching all the violations in a timely manner is
hard.

Freezing at first use is too late for a good exception, but any
earlier has surprising restrictions.

There is no good way to realize that a constant has changed after the freeze.


Bad Case Option (4) -- Ignore problems
--

This is for optimization; go ahead and ignore any problems you can.
Maybe that branch will never be taken...  Ironically, this is also
largely school I, since it matches the if semantics.


Bad Case Option (5) -- ad hoc mixture
-

Pick an arbitrary set of rules, and follow it.

Guido is currently leaning towards this, with the rules being freeze
at definition, raise for unhashable, ignore later changes, undecided
on overlapping ranges.

The disadvantage is that people can cheat with non-constant
expressions.  Sometimes, this will work out great.  Sometimes it will
lead to nasty non-localized bugs.  We have to explain exactly which
cheats are allowed, and that explanation could get byzantine.


Bad Case Option (6) -- Undefined


Undefined behavior.  We don't yet know which strategy (or mix of
strategies) is best.  So don't lock ourselves (and Jython, and PyPy,
and IronPython, and ShedSkin, and ...) into the wrong strategy.

The down side is that people may start to count on the actual behavior
anyhow; then (in practice) we might just have Bad Case Option (5)
without documentation.

-jJ
___
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] Switch statement - handling errors

2006-06-27 Thread Guido van Rossum
On 6/27/06, Jim Jewett [EMAIL PROTECTED] wrote:
 On 6/26/06, Guido van Rossum [EMAIL PROTECTED] wrote:
  I like Python's rules to be simple, and I
  prefer to occasionally close off a potential optimization path in the
  sake of simplicity.

 (Almost) everyone agrees that the case expressions SHOULD be run-time
 constants.  The disagreements are largely over what to do when this
 gets violated.

Thanks for the elaboration. I'm not sure how to respond except to
correct your representation of my position:

 Bad Case Option (1) -- Accept everything
 

 Readability is everything.  Switch/case tells you that every branch is
 using similar predicates on the same variable.  If that variable or
 predicate can't be easily optimized, then so what -- it is still
 better to read.  (Largely School Ia)


 Bad Case Option (2) -- Accept very little
 -

 Enforce good case expressions.  (Raymond's proposal)  This does the
 right thing when it works, but it is initially very restricted -- and
 a crippled case statement may be worse than none at all.


 Bad Case Option (3) -- Raise Exceptions
 ---

 Flag bugs early.  The semantics require non-overlapping hashable
 constants, so raise an exception if this gets violated.  This does the
 right thing, but catching all the violations in a timely manner is
 hard.

 Freezing at first use is too late for a good exception, but any
 earlier has surprising restrictions.

 There is no good way to realize that a constant has changed after the 
 freeze.


 Bad Case Option (4) -- Ignore problems
 --

 This is for optimization; go ahead and ignore any problems you can.
 Maybe that branch will never be taken...  Ironically, this is also
 largely school I, since it matches the if semantics.


 Bad Case Option (5) -- ad hoc mixture
 -

 Pick an arbitrary set of rules, and follow it.

 Guido is currently leaning towards this, with the rules being freeze
 at definition, raise for unhashable, ignore later changes, undecided
 on overlapping ranges.

Actually I'm all for flagging overlapping changes as errors when the
dict is frozen.

 The disadvantage is that people can cheat with non-constant
 expressions.  Sometimes, this will work out great.  Sometimes it will
 lead to nasty non-localized bugs.  We have to explain exactly which
 cheats are allowed, and that explanation could get byzantine.

Actually I would simply explain that all cheats are frowned upon, just
like all side effects in case expressions.



 Bad Case Option (6) -- Undefined
 

 Undefined behavior.  We don't yet know which strategy (or mix of
 strategies) is best.  So don't lock ourselves (and Jython, and PyPy,
 and IronPython, and ShedSkin, and ...) into the wrong strategy.

 The down side is that people may start to count on the actual behavior
 anyhow; then (in practice) we might just have Bad Case Option (5)
 without documentation.

 -jJ



-- 
--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] Switch statement - handling errors

2006-06-27 Thread Ka-Ping Yee
On Tue, 27 Jun 2006, Jim Jewett wrote:
 (Almost) everyone agrees that the case expressions SHOULD be run-time
 constants.  The disagreements are largely over what to do when this
 gets violated.

I like your summary and understood most of it (options 1, 2, 3, 5, 6).
The only part i didn't understand was this:

 Bad Case Option (4) -- Ignore problems
 --

 This is for optimization; go ahead and ignore any problems you can.
 Maybe that branch will never be taken...  Ironically, this is also
 largely school I, since it matches the if semantics.

Could you elaborate on what this means?  Does ignore any problems
mean even if a case value changes, pretend it didn't change?  But
that wouldn't match the 'if' semantics, so i'm not sure what you
had in mind.

 Bad Case Option (6) -- Undefined
 
[...]
 The down side is that people may start to count on the actual behavior
 anyhow; then (in practice) we might just have Bad Case Option (5)
 without documentation.

I agree with this last paragraph.  Option 6 seems the most risky of all.


-- ?!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] Switch statement - handling errors

2006-06-27 Thread Guido van Rossum
On 6/27/06, Jim Jewett [EMAIL PROTECTED] wrote:
 Bad Case Option (5) -- ad hoc mixture
 -

 Pick an arbitrary set of rules, and follow it.

 Guido is currently leaning towards this, with the rules being freeze
 at definition, raise for unhashable, ignore later changes, undecided
 on overlapping ranges.

 The disadvantage is that people can cheat with non-constant
 expressions.  Sometimes, this will work out great.  Sometimes it will
 lead to nasty non-localized bugs.  We have to explain exactly which
 cheats are allowed, and that explanation could get byzantine.

A solution that is often offered in situations like this: Pychecker
(or something like it) can do a much more thorough check. It should be
easy for Pychecker to keep track of the constancy of variables.

IMO my proposal has no cheats. It has well-defined semantics. Maybe
not the semantics you'd like to see, but without ESP built into the
compiler that's impossible. If you stick to the simple rule constants
only then you won't see any semantics surprises. Just stay away from
anything where you're not sure whether it's really a constant, and
you'll be fine. If on the other hand you want to explore the
boundaries of the semantics, we'll give you one simple rule, and you
can verify that that rule is indeed all there is.

-- 
--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


[Python-Dev] Switch statement

2006-06-26 Thread Jim Jewett
In http://mail.python.org/pipermail/python-dev/2006-June/066475.html
Nick Coghlan wrote:

 (Unlike Jim, I have no problems with restricting switch statements to
 hashable objects and building the entire jump table at once - if what you want
 is an arbitrary if-elif chain, then write one!)

I haven't been clear.  I don't object to building the entire table at
once.  I object to promising that this will happen, which forbids
other implementations from using certain optimizations.

I would prefer something like:

There is no guarantee on how often or when the case statements will be
evaluated, except that it will be after the enclosing scope exists and
before the relevant test is needed.  If a case expression has side
effects, the behavior with respect to these side effects is explicitly
undefined.

-jJ
___
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] Switch statement

2006-06-26 Thread Guido van Rossum
On 6/26/06, Jim Jewett [EMAIL PROTECTED] wrote:
 In http://mail.python.org/pipermail/python-dev/2006-June/066475.html
 Nick Coghlan wrote:

  (Unlike Jim, I have no problems with restricting switch statements to
  hashable objects and building the entire jump table at once - if what you 
  want
  is an arbitrary if-elif chain, then write one!)

 I haven't been clear.  I don't object to building the entire table at
 once.  I object to promising that this will happen, which forbids
 other implementations from using certain optimizations.

 I would prefer something like:

 There is no guarantee on how often or when the case statements will be
 evaluated, except that it will be after the enclosing scope exists and
 before the relevant test is needed.  If a case expression has side
 effects, the behavior with respect to these side effects is explicitly
 undefined.

This is the kind of language that makes C++ and Fortrans standards so
difficult to interpret. I like Python's rules to be simple, and I
prefer to occasionally close off a potential optimization path in the
sake of simplicity. For example, I like left-to-right evaluation of
operands and function arguments. The C++/Fortran style weasel words to
allow optimizers to do sneaky stuff aren't really wort the trouble
they can create in Python, where even the best optimization produces
code that's much slower than C. In practice, most users observe the
behavior of the one compiler they use, and code to that standard; so
allowing different compilers or optimization levels to do different
things when functions have side effects is just asking for surprises.

In Python, the big speedups come from a change in algorithm. That's
why it's imprtant to me that switch be dict-based (O(1)), as an
alternative to an if/elif chain (O(N)). (The implementation doesn't
have to use a regular dict, though; the important part is that it's
based on hash() and __eq__().)

-- 
--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] Switch statement

2006-06-25 Thread Guido van Rossum
On 6/24/06, Nick Coghlan [EMAIL PROTECTED] wrote:
 [...] a syntactic nit that Eric Sumner pointed out. Since
 it involves iteration over x to populate the jump table rather than doing a
 containment test on x, using 'case in x' is misleading. It would be better
 written as 'case *x'.

 Then:
'case 1:' == a switch value of 1 will jump to this case
'case 1, 2:'  == a switch value of 1 or 2 will jump to this case
'case *x' == any switch value in x will jump to this case
'case *x, *y' == any switch value in x or y will jump to this case

I'm +0 on this idea, or something similar (maybe my original 'case in'
syntax with 'in' replaced by '*'.

I'm going to have to sleep on Nick's 'once' proposal (which deserves a
separate thread).

-- 
--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] Switch statement

2006-06-25 Thread Fredrik Lundh
Phillip J. Eby wrote:

 I don't see this as much of a problem, really: we can simply restrict
 the optimization to well-known data types (homogenous switches using
 integers or strings should cover 99.9% of all practical cases), and then
 add an opcode that checks uses a separate dispatch object to check if
 fast dispatch is possible, and place that before an ordinary if/elif
 sequence.
 
 What about switches on types?  Things like XML-RPC and JSON want to be able 
 to have a fast switch on an object's type and fall back to slower tests 
 only for non-common cases.

good point (and nice example).

 for t in obtype.__mro__:
  switch t:
  case int: ...; break
  case str: ...; break
  else:
  continue
  else:
  # not a recognized type

but I wonder how confusing the break inside switch terminates the outer 
loop pattern would be to a C programmer...

/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] Switch statement

2006-06-25 Thread Greg Ewing
Guido van Rossum wrote:
 I'm currently leaning
 towards making static expressions outside a function illegal and limit
 switches outside a function to compile-time-constant expressions.

I'm not sure I like the idea of having things that
are illegal outside a function, because it can be a
nuisance for code refactoring.

I'd be happy if case worked at the top level, but
wasn't any faster than if-elses. That wouldn't be
so bad -- top-level code is already slower due to
global variable accesses.

Also I don't care what happens if you change the
case values of a top-level case. It's undefined
behaviour anyway.

--
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] Switch statement

2006-06-25 Thread Guido van Rossum
On 6/25/06, Greg Ewing [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  I'm currently leaning
  towards making static expressions outside a function illegal and limit
  switches outside a function to compile-time-constant expressions.

 I'm not sure I like the idea of having things that
 are illegal outside a function, because it can be a
 nuisance for code refactoring.

 I'd be happy if case worked at the top level, but
 wasn't any faster than if-elses. That wouldn't be
 so bad -- top-level code is already slower due to
 global variable accesses.

 Also I don't care what happens if you change the
 case values of a top-level case. It's undefined
 behaviour anyway.

Fair enough. I wasn't leaning very strongly 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] Switch statement

2006-06-25 Thread BJörn Lindqvist
On 6/23/06, Edward C. Jones [EMAIL PROTECTED] wrote:
 Python is a beautiful simple language with a rich standard library.
 Python has done fine without a switch statement up to now. Guido left it
 out of the original language for some reason (my guess is simplicity).
 Why is it needed now? What would be added next: do while or goto? The
 urge to add syntax should be resisted unless there is a high payoff
 (such as yield).

 There are much better ways for the developers to spend their time and
 energy (refactoring os comes to mind).

 Please keep Python simple.

 -1 on the switch statement.

I agree. IMHO switch is a useless statement which can cause many
problems in any language. It misleads programmers to dispatch in the
wrong way. If you have switch with  5 cases, an if-elif chain fits
just fine. If the switch is larger use a dictionary that maps values
to functions. In C, many times a switch block starts small (40 lines)
but grows as the number of values to dispatch on increases. Soon it
becomes a 500 line monstrosity that is impossible to refactor because
variables from the enclosing space is used frivolously.

I don't get the speed argument either. Who cares that if-elif-chains
are O(n) and switch O(1)? If n  10 you are doing something wrong
anyway. I don't think I have ever seen in any language a switch
construct that, barring speed concerns, wouldn't be better written
using any other dispatch mechanism than switch.

-- 
mvh Björn
___
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] Switch statement

2006-06-24 Thread Nick Coghlan
The current train of thought seems to be to handle a switch statement as 
follows:

   1. Define switch explicitly as a hash table lookup, with the hash table 
built at function definition time

   2. Allow expressions to be flagged as 'static' to request evaluation at 
def-time

   3. Have the expressions in a case clause be implicitly flagged as static

   4. Allow 'case in' to be used to indicate that a case argument is to be 
iterated and all its values added to the current case

   5. Static names are not needed - static expressions must refer solely to 
literals and non-local names

An issue with Point 4 is a syntactic nit that Eric Sumner pointed out. Since 
it involves iteration over x to populate the jump table rather than doing a 
containment test on x, using 'case in x' is misleading. It would be better 
written as 'case *x'.

Then:
   'case 1:' == a switch value of 1 will jump to this case
   'case 1, 2:'  == a switch value of 1 or 2 will jump to this case
   'case *x' == any switch value in x will jump to this case
   'case *x, *y' == any switch value in x or y will jump to this case

For the remaining points, I share Jim Jewett's concern that 'function 
definition time' is well defined for function scopes only - a better 
definition of the evaluation time is needed so that it works for other code as 
well. (Unlike Jim, I have no problems with restricting switch statements to 
hashable objects and building the entire jump table at once - if what you want 
is an arbitrary if-elif chain, then write one!)

I'd also like to avoid confusing the code execution order too much. People 
objected to the out-of-order evaluation in statement local namespaces - what's 
being proposed for static expressions is significantly worse.

So here's a fleshed out proposal for 'once expressions' that are evaluated the 
first time they are encountered and cached thereafter.

Once expressions

   An expression of the form 'once EXPR' is evaluated exactly once for a given 
scope. Precedence rules are as for yield expressions.
   Evaluation occurs the first time the expression is executed. On all 
subsequent executions, the expression will return the same result as was 
returned the first time.
   Referencing a function local variable name from a static expression is a 
syntax error. References to module globals, to closure variables and to names 
not bound in the module at all are fine.

Justifying evaluation at first execution time
-
   With evaluation at first execution time, the semantics are essentially the 
same in all kinds of scope (module, function, class, exec). When the 
evaluation time is defined in terms of function definition time, it is very 
unclear what happens when there is no function definition involved.
   With the once-per-scope definition above, the potentially confusing cases 
that concerned Guido would have the behaviour he desired.

  def foo(c):
...   print once c
...
SyntaxError: Cannot use local variable 'c' in once expression

   The rationale for disallowing function local variables in a once expression 
is that next time the function is executed, the local variables are expected 
to contain different values, so it is unlikely that any expression depending 
on them would give the same answer. Builtins, module globals and closure 
variables, on the other hand, will typically remain the same across 
invocations of a once expression. So the rationale for the syntactic 
restriction against using local variables is still there, even though the 
local variables may actually contain valid data at the time the once 
expression is executed. This syntactic restriction only applies to function 
locals so that a module level once expression is still useful.

  def foo(c):
...   def bar():
... print once c
...   return bar
...
  b1 = foo(1)
  b2 = foo(2)
  b1()
1
  b2()
2

   For this case, the important point is that execution of the once expression 
is once per scope, not once per program. Since running the function definition 
again creates a different function object, the once expression gets executed 
again the first time that function is called.

   An advantage of first time execution for functions is that it can be used 
to defer calculation of expensive default values to the first time they're 
needed.

  def foo(c=None):
...   if c is None:
... c = once calculate_expensive_default()
...   # etc
...

   With function definition time evaluation, the expensive default would 
always be calculated even if the specific application always provided an 
argument to the function and hence never actually needed the default.

   The one downside to this first time execution approach is that it means 
'once' is NOT a solution to the early-binding vs late-binding problem for 
closure variables. Forcing early binding would still require abuse of function 
defaults, or a compiler directive along the lines of the current 'global'. I 

Re: [Python-Dev] Switch statement

2006-06-24 Thread Fredrik Lundh
Josiah Carlson wrote:

 This is a good thing, because if switch/case ends up functionally
 identical to if/elif/else, then it has no purpose as a construct.

there's no shortage of Python constructs that are functionally identical 
to existing constructs.  as with all syntactic sugar, the emphasis 
should be on what the programmer wants to express, not how you can 
artificially constrain the implementation to make the new thing slightly 
different from what's already in there.

and the point of switch/case is to be able to say I'm going to dispatch 
on a single value in a concise way; the rest is optimizations.

/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] Switch statement

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

  just map

  switch EXPR:
  case E1:
  ...
  case in E2:
  ...
  else:
  ...

 to

  VAR = EXPR
  if VAR == E1:
  ...
  elif VAR in E2:
  ...
  else:
  ...

 where VAR is a temporary variable, and case and case-in clauses can be
 freely mixed, and leave the rest to the code generator.  (we could even
 allow switch EXPR [as VAR] to match a certain other sugar construct).
 
 This used to be my position. I switched after considering the
 alternatives for what should happen if either the switch expression or
 one or more of the case expressions is unhashable.

I don't see this as much of a problem, really: we can simply restrict 
the optimization to well-known data types (homogenous switches using 
integers or strings should cover 99.9% of all practical cases), and then 
add an opcode that checks uses a separate dispatch object to check if 
fast dispatch is possible, and place that before an ordinary if/elif 
sequence.

the dispatch object is created when the function object is created, 
along with default values and statics.  if fast dispatch cannot be used 
for a function instance, the dispatch object is set to None, and the 
dispatch opcode turns into a NOP.

(each switch statement should of course have it's own dispatch object).

/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] Switch statement

2006-06-24 Thread Phillip J. Eby
At 07:04 PM 6/24/2006 +0200, Fredrik Lundh wrote:
I don't see this as much of a problem, really: we can simply restrict
the optimization to well-known data types (homogenous switches using
integers or strings should cover 99.9% of all practical cases), and then
add an opcode that checks uses a separate dispatch object to check if
fast dispatch is possible, and place that before an ordinary if/elif
sequence.

What about switches on types?  Things like XML-RPC and JSON want to be able 
to have a fast switch on an object's type and fall back to slower tests 
only for non-common cases.  For that matter, you can build an effective 
multiway isinstance() check using something like:

 for t in obtype.__mro__:
 switch t:
 case int: ...; break
 case str: ...; break
 else:
 continue
 else:
 # not a recognized type

This is essentially what RuleDispatch does in generic functions' dispatch 
trees now, albeit without the benefit of a switch statement or opcode.

___
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] Switch statement

2006-06-24 Thread Ka-Ping Yee
On Fri, 23 Jun 2006, Josiah Carlson wrote:
 This is a good thing, because if switch/case ends up functionally
 identical to if/elif/else, then it has no purpose as a construct.

This doesn't make sense as a rule.

Consider:

If x.y ends up functionally identical to getattr(x, 'y'),
 then it has no purpose as a construct.

If print x ends up functionally identical to import sys;
 sys.stdout.write(str(x) + '\n'), then it has no purpose as
 a construct.

What matters is not whether it's *functionally* identical.  What
matters is whether it makes more sense to the reader and has a
meaning that is likely to be what the writer wanted.

Evaluate the switch expression just once is a semantic win.

Evaluate the switch expression just once, but throw an exception
if the result is not hashable is a weaker semantic win.  (How
often is that what the writer is thinking about?)

Throw an exception at compile time if the cases overlap is also
a weaker semantic win.  (How often is this an actual mistake that
the writer wants to be caught at compile time?)

Use the case values computed at compile time, not at runtime doesn't
seem like much of a win.  (How often will this be what the writer
intended, as opposed to a surprise hiding in the bushes?)


-- ?!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] Switch statement

2006-06-24 Thread Josiah Carlson

Ka-Ping Yee [EMAIL PROTECTED] wrote:
 On Fri, 23 Jun 2006, Josiah Carlson wrote:
  This is a good thing, because if switch/case ends up functionally
  identical to if/elif/else, then it has no purpose as a construct.
 
 This doesn't make sense as a rule.
 
 Consider:
 
 If x.y ends up functionally identical to getattr(x, 'y'),
  then it has no purpose as a construct.
 
 If print x ends up functionally identical to import sys;
  sys.stdout.write(str(x) + '\n'), then it has no purpose as
  a construct.

I agree with you completely, it doesn't make sense as a rule, but that
was not its intent.  Note that I chose specific values of X and Y in if
X is functionally identical to Y, then it has no purpose as a construct
such that it did make sense.


 What matters is not whether it's *functionally* identical.  What
 matters is whether it makes more sense to the reader and has a
 meaning that is likely to be what the writer wanted.
 
 Evaluate the switch expression just once is a semantic win.
 
 Evaluate the switch expression just once, but throw an exception
 if the result is not hashable is a weaker semantic win.  (How
 often is that what the writer is thinking about?)
 
 Throw an exception at compile time if the cases overlap is also
 a weaker semantic win.  (How often is this an actual mistake that
 the writer wants to be caught at compile time?)
 
 Use the case values computed at compile time, not at runtime doesn't
 seem like much of a win.  (How often will this be what the writer
 intended, as opposed to a surprise hiding in the bushes?)

The reasons by themselves don't seem to make sense, until you look at
them in the scope from which the decisions were made.  Just like
the word Excelsior makes no sense until you hear Minnesota.

Those final three rules, when seen in the context of the rest of the
conversation, and with the understanding that one of the motivating
purposes is to improve execution time, do offer methods and mechanisms
to answer those motivations.


 - 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] Switch statement

2006-06-24 Thread Ron Adam
Fredrik Lundh wrote:
 Guido van Rossum wrote:
 
   just map
  switch EXPR:
  case E1:
  ...
  case in E2:
  ...
  else:
  ...

 to

  VAR = EXPR
  if VAR == E1:
  ...
  elif VAR in E2:
  ...
  else:
  ...

 where VAR is a temporary variable, and case and case-in clauses can be
 freely mixed, and leave the rest to the code generator.  (we could even
 allow switch EXPR [as VAR] to match a certain other sugar construct).

 This used to be my position. I switched after considering the
 alternatives for what should happen if either the switch expression or
 one or more of the case expressions is unhashable.

 I don't see this as much of a problem, really: we can simply restrict 
 the optimization to well-known data types (homogenous switches using 
 integers or strings should cover 99.9% of all practical cases)

+1  This would keep it simple to use.


A possibility that hasn't been mentioned yet is to supply a precomputed 
jump table to a switch explicitly.

 table = {expr1:1, expr2:2, ... }

 for value in data:
 switch table[value]:
case 1: ...
 case 2: ...
 ...
 else: ...

(I prefer indented case's, but it's not the point here.  I can get use 
them it not being indented.)

It is an easy matter to lift evaluation of the switch table expressions 
out of inner loops or even out of functions. (if it's needed of course)


Or an alternate form may allow a pre-evaluated jump table to be 
explicitly substituted directly at the time of use. (would this be 
possible?)

 def switcher(value, table):
switch value, table:
   case 1: ...
   case 2: ...
   ...
   else: ...


Cheers,
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] Switch statement

2006-06-24 Thread Greg Ewing
Phillip J. Eby wrote:

 1. case (literal|NAME) is the syntax for equality testing -- you can't 
 use an arbitrary expression, not even a dotted name.

That's too restrictive. I want to be able to write
things like

   class Foods:
 Spam = 1
 Eggs = 2
 Ham = 3

  ...

 switch f:
   case Foods.Spam:
 ...
   case Foods.Eggs:
 ...

--
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] Switch statement

2006-06-23 Thread Fredrik Lundh
Phillip J. Eby wrote:

 I think I like it.  I was confused by what Fredrik meant by const, but 
 your renaming it to static makes more sense to me;

footnote: I suggested static in my list of use cases; while const 
makes sense in many cases, static makes more sense for things like this:

  def foo(value):
  table = const {
  1: one,
  2: two,
  3: fie.fum,
  }
 
 (maybe static would be a better keyword?)

...at least for C/C++ heads; if you look things up in a dictionary, I'd 
say that the noun constant, in the meaning

2. a. A quantity assumed to have a fixed value in a
  specified mathematical context.
   b. An experimental or theoretical condition, factor,
  or quantity that does not vary or that is regarded
  as invariant in specified circumstances.

makes at least as much sense as the adjective static:

1. a. Having no motion; being at rest; quiescent.
   b. Fixed; stationary.

 Unfortunately this would probably cause people to write

   switch x:
 case static re.DOTALL: ...
 case static re.IGNORECASE: ...

 which is just more work to get the same effect as the
 def-time-switch-freezing proposal.
 
 Without the static, the reordering of execution isn't obvious.  But 
 perhaps that could be lived with, if the explanation was, well, static
  is implied by case.

I'd still prefer the explicit is better than implicit route, approach 
switch/case (if added) is defined in terms of if/elif, and optimizations 
are handled by the optimizer/code generator.

/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] Switch statement

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

 That sounds like a good solution all around. I hope that others can
 also find themselves in this.
 
 (1) An expression of the form 'static' atom has the semantics of
 evaluating the atom at the same time as the nearest surrounding
 function definition. If there is no surrounding function definition,
 'static' is a no-op and the expression is evaluated every time.
 [Alternative 1: this is an error] [Alternative 2: it is evaluated
 before the module is entered; this would imply it can not involve any
 imported names but it can involve builtins] [Alternative 3:
 precomputed the first time the switch is entered]

+0.5 on this (still looking for some obvious drawback).

as for static in non-local scopes, an error feels more pythonic, but 
that would complicate things if you want to move code from a local to a 
global context (but how often do you do that ?).  alternative 2 and 3 
feels too magic, again.

 (2) All case expressions in a switch have an implied 'static'.

I'm still -0 on implied static.  and only +0 on switch/case, in general. 
  but it's growing on me.

(now, if you're written implied 'break', I'm all for it)

 (3) A switch is implemented using a dict which is precomputed at the
 same time its static expressions are precomputed. The switch
 expression must be hashable. Overlap between different cases will
 raise an exception at precomputation time.

+0 on switch/case, but -0.5 on a in terms of implementation rather 
than in terms of existing language constructs approach.

as I mentioned before, I'd prefer if the switch/case/case-in/else was 
defined in terms of a corresponding if/elif/else construct (but where 
the controlling expression is only evaluated once).

after all, Python's a dynamic language, and I'm not convinced that I 
would never want to use dynamically evaluated case values.  just map

 switch EXPR:
 case E1:
 ...
 case in E2:
 ...
 else:
 ...

to

 VAR = EXPR
 if VAR == E1:
 ...
 elif VAR in E2:
 ...
 else:
 ...

where VAR is a temporary variable, and case and case-in clauses can be 
freely mixed, and leave the rest to the code generator.  (we could even 
allow switch EXPR [as VAR] to match a certain other sugar construct).

I'm also a KR guy, so switch/case/case-in/else should all have the same 
indent.  anything else is just sloppy design.

 Independent from this, I wonder if we also need static names of the form
 
   static name = expression
 
 which would be similar to
 
   name = static (expression)
 
 but also prevents name from being assigned to elsewhere in the same scope.

-0 from here; I don't see an obvious need for static names, but it may 
grow on me.

 Also, I haven't heard a lot of thumbs up or down on the idea of using
 
   case X:
 
 to indicate a single value and
 
   case in S:
 
 to indicate a sequence of values.

+1 from here.  it's obvious, useful, and therefore perfectly pythonic.

/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] Switch statement

2006-06-23 Thread Fredrik Lundh
Fredrik Lundh wrote:

 I'd still prefer the explicit is better than implicit route, approach 
 switch/case (if added) is defined in terms of if/elif, and optimizations 
 are handled by the optimizer/code generator.

s/approach/where/

/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] Switch statement

2006-06-23 Thread Fredrik Lundh
Fredrik Lundh wrote:

 (now, if you're written implied 'break', I'm all for it)

note to self: the fact that it's a holiday doesn't mean that you should 
post before you'd had enough coffee.

/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] Switch statement

2006-06-23 Thread Josiah Carlson

Guido van Rossum [EMAIL PROTECTED] wrote:
 (1) An expression of the form 'static' atom has the semantics of
 evaluating the atom at the same time as the nearest surrounding
 function definition. If there is no surrounding function definition,
 'static' is a no-op and the expression is evaluated every time.
 [Alternative 1: this is an error] [Alternative 2: it is evaluated
 before the module is entered; this would imply it can not involve any
 imported names but it can involve builtins] [Alternative 3:
 precomputed the first time the switch is entered]

I'm +1 on alternative 1, but -1 on all others, with a small caveat that
I'll mark with * later on.


 (2) All case expressions in a switch have an implied 'static'.

+1

 (3) A switch is implemented using a dict which is precomputed at the
 same time its static expressions are precomputed. The switch
 expression must be hashable. Overlap between different cases will
 raise an exception at precomputation time.

+1 (As I was catching up on the flurry of emails from yesterday this
morning, I noticed to my surprise that you came around to precisely what
I had hoped for in a switch/case statement; I'm going to have to try not
posting on a subject more often .5 wink)

 Independent from this, I wonder if we also need static names of the form
 
   static name = expression
 
 which would be similar to
 
   name = static (expression)
 
 but also prevents name from being assigned to elsewhere in the same scope.

* I don't particularly care for the literal syntax of static.  I like
the /idea/, but I don't believe that it is as useful as people think it
is.  Let me explain.  Given your previously proposed 'all cases have an
implied static', that handles the switch/case statement, the purpose of
'static' is to explain what happens to the switch/case statement, not
that people would actually use it as such in the switch/case example (as
it is implied, and people are insane about trying to reduce how much
they type).

For general variables, like say; math.pi, re.DOTALL, sys.maxint, len,
int, Exception, etc., many of them are merely references to their values,
that is, there are no value manipulations.  This case is quite
conveniently covered by Raymond's Decorator for BindingConstants at
compile time, a sexy decorator available in the cookbook [1].  That
decorator can handle all of the non-modifying value assignments, and in
the case of Frederick's previously described:

if value  const (math.pi / 2):
...

... a small modification to Raymond's recipe that allows keyword
arguments (on the decorator) would preserve the beauty of the function
definition, at the cost of an uglier decorator.

@make_constants(math_pi_2=(math.pi / 2))
def foo(value):
if value  math_pi_2:
...

Now, it's not as slick as a static unary operator, but it handles the
simple references case quite well, and can be hacked to handle the
saving of expressions without significant difficulty, though such
uglifies the decorator call significantly.  If a variant of that
decorator were available in the standard library, maybe with simple
variants, I believe much of the general talk about 'static' will go away. 
I could certainly be wrong, but that's ok too.


 Also, I haven't heard a lot of thumbs up or down on the idea of using
 
   case X:
 
 to indicate a single value and
 
   case in S:
 
 to indicate a sequence of values.

+1


 (I'm not counting all the hypergeneralizations that were proposed like
 
   case == X:
   case  X:
   case is X:
   case isinstance X:
 
 since I'm -1 on all those, no matter how nicely they align.

The 'case == X' was cute, though if it was an alternative spelling of
'case X', I doubt it would be used terribly often.  Regardless, I'm -1
on all other cases, and would not be concerned to lose the '== X'
version.

 - Josiah

[1] http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/277940

___
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] Switch statement

2006-06-23 Thread Alex Martelli
On 6/22/06, Guido van Rossum [EMAIL PROTECTED] wrote:
   ...
 (1) An expression of the form 'static' atom has the semantics of
 evaluating the atom at the same time as the nearest surrounding
 function definition. If there is no surrounding function definition,
 'static' is a no-op and the expression is evaluated every time.
 [Alternative 1: this is an error] [Alternative 2: it is evaluated
 before the module is entered; this would imply it can not involve any
 imported names but it can involve builtins] [Alternative 3:
 precomputed the first time the switch is entered]

+1, preferably with alternative 1.  I've occasionally (ab)used the
fact that default values are computed at def time to get similar
semantics, but that (whence the ab) has all sorts of issues (such as
exposing arguments you really do NOT want to be passed).


 (2) All case expressions in a switch have an implied 'static'.

 (3) A switch is implemented using a dict which is precomputed at the
 same time its static expressions are precomputed. The switch
 expression must be hashable. Overlap between different cases will
 raise an exception at precomputation time.

+0, just because I care about switch only up to a point!-)


 Independent from this, I wonder if we also need static names of the form

   static name = expression

 which would be similar to

   name = static (expression)

 but also prevents name from being assigned to elsewhere in the same scope.

Lovely!!!  Definitely +1.  Could perhaps THIS use of static be allowed
even outside of a def?  I'd just love to have such static names in
modules and classes, too (with runtime checks of errant assignments,
if needed).


 Also, I haven't heard a lot of thumbs up or down on the idea of using

   case X:

 to indicate a single value and

   case in S:

 to indicate a sequence of values.

 (I'm not counting all the hypergeneralizations that were proposed like

   case == X:
   case  X:
   case is X:
   case isinstance X:

 since I'm -1 on all those, no matter how nicely they align.

Agreed on the generalizations, but allowing (just) case == X and
case in S looks more readable to me than case X and case in S.
Since I'm not overly focused on switch/case anyway, _and_ this choice
is just about syntax sugar anyway, my preference's mild!-)


Alex
___
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] Switch statement

2006-06-23 Thread Guido van Rossum
On 6/23/06, Josiah Carlson [EMAIL PROTECTED] wrote:

 Guido van Rossum [EMAIL PROTECTED] wrote:
  (1) An expression of the form 'static' atom has the semantics of
  evaluating the atom at the same time as the nearest surrounding
  function definition. If there is no surrounding function definition,
  'static' is a no-op and the expression is evaluated every time.
  [Alternative 1: this is an error] [Alternative 2: it is evaluated
  before the module is entered; this would imply it can not involve any
  imported names but it can involve builtins] [Alternative 3:
  precomputed the first time the switch is entered]

 I'm +1 on alternative 1, but -1 on all others, with a small caveat that
 I'll mark with * later on.

I'm beginning to lean in that direction myself. A clean rule for
switches would be that if it's not inside a function, the cases must
be compile-time constant expressions.

  (2) All case expressions in a switch have an implied 'static'.

 +1

  (3) A switch is implemented using a dict which is precomputed at the
  same time its static expressions are precomputed. The switch
  expression must be hashable. Overlap between different cases will
  raise an exception at precomputation time.

 +1 (As I was catching up on the flurry of emails from yesterday this
 morning, I noticed to my surprise that you came around to precisely what
 I had hoped for in a switch/case statement; I'm going to have to try not
 posting on a subject more often .5 wink)

No kidding. There is such a thing as too much heat. I need to do this
more often myself, too!

  Independent from this, I wonder if we also need static names of the form
 
static name = expression
 
  which would be similar to
 
name = static (expression)
 
  but also prevents name from being assigned to elsewhere in the same scope.

 * I don't particularly care for the literal syntax of static.

What do you mean by literal syntax of static? Do you mean 'static'
atom or 'static'  name '=' expression? Or something else?

 I like
 the /idea/, but I don't believe that it is as useful as people think it
 is.  Let me explain.  Given your previously proposed 'all cases have an
 implied static', that handles the switch/case statement, the purpose of
 'static' is to explain what happens to the switch/case statement, not
 that people would actually use it as such in the switch/case example (as
 it is implied, and people are insane about trying to reduce how much
 they type).

I'm all for typing less if it makes things clearer for the reader. I'm
not for reductions in what you type at the expense of readability.
Often, reducing redundant boiler plate is of the first category, since
the reader must just skip the boiler plate if it's explicitly typed.

 For general variables, like say; math.pi, re.DOTALL, sys.maxint, len,
 int, Exception, etc., many of them are merely references to their values,
 that is, there are no value manipulations.  This case is quite
 conveniently covered by Raymond's Decorator for BindingConstants at
 compile time, a sexy decorator available in the cookbook [1].  That
 decorator can handle all of the non-modifying value assignments, and in
 the case of Frederick's previously described:

But it is an absolutely yucky approach. It modifies byte code. That
makes it break in future Python versions (Python's byte code is not
standardized across versions), as well in Jython, IronPython, and
sandboxed Python (which will make a come-back, see Brett's post).

If it's as valuable as to let people devise the crap in that cookbook
entry (no offense, I'm sure it's a great intellectual accomplishment,
but it's fundamentally the wrong approach) then it's worth adding
something to the language to do it right. As the cookbook discussion
mentions, the decorator assumes that all globals are constant. That is
way too implicit for me.

(IOW, the existence of that cookbook entry proves to me that the
language needs to support something like this explicitly.)

 if value  const (math.pi / 2):
 ...

 ... a small modification to Raymond's recipe that allows keyword
 arguments (on the decorator) would preserve the beauty of the function
 definition, at the cost of an uglier decorator.

 @make_constants(math_pi_2=(math.pi / 2))
 def foo(value):
 if value  math_pi_2:
 ...

Realistically that would be way too verbose. Note how the string
approximating math...pi...2 now occurs three times in the code where
Fredrik's example had it only once!

 Now, it's not as slick as a static unary operator, but it handles the
 simple references case quite well, and can be hacked to handle the
 saving of expressions without significant difficulty, though such
 uglifies the decorator call significantly.  If a variant of that
 decorator were available in the standard library, maybe with simple
 variants, I believe much of the general talk about 'static' will go away.
 I could certainly be wrong, but that's ok too.

It's fundamentally the wrong 

Re: [Python-Dev] Switch statement

2006-06-23 Thread Guido van Rossum
On 6/23/06, Alex Martelli [EMAIL PROTECTED] wrote:
 On 6/22/06, Guido van Rossum [EMAIL PROTECTED] wrote:
  Independent from this, I wonder if we also need static names of the form
 
static name = expression
 
  which would be similar to
 
name = static (expression)
 
  but also prevents name from being assigned to elsewhere in the same scope.

 Lovely!!!  Definitely +1.  Could perhaps THIS use of static be allowed
 even outside of a def?  I'd just love to have such static names in
 modules and classes, too (with runtime checks of errant assignments,
 if needed).

It would provide no speed advantage, and I don't see how the
staticness would be transferred upon import into another module.
Runtime checks of errant assignments would be relatively easy: trap
this in the module setattr operation, and henceforth let
module.__dict__ return a read-only dict wrapper. (Except that would
break exec E in globals(). I guess it would have to be a dict
wrapper that only makes those specific keys read-only...)

-- 
--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] Switch statement

2006-06-23 Thread Josiah Carlson

Alex Martelli [EMAIL PROTECTED] wrote:
 On 6/22/06, Guido van Rossum [EMAIL PROTECTED] wrote:
  Independent from this, I wonder if we also need static names of the form
 
static name = expression
 
  which would be similar to
 
name = static (expression)
 
  but also prevents name from being assigned to elsewhere in the same scope.
 
 Lovely!!!  Definitely +1.  Could perhaps THIS use of static be allowed
 even outside of a def?  I'd just love to have such static names in
 modules and classes, too (with runtime checks of errant assignments,
 if needed).

The problem is that there would need to be a change to modules to be
more class-like (read-only properties), as module.foo = x would need
to raise an exception if foo was static in module.

 - 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] Switch statement

2006-06-23 Thread M.-A. Lemburg
Georg Brandl wrote:
 M.-A. Lemburg wrote:
 
 A nice side-effect would be that could easily use the
 same approach to replace the often used default-argument-hack,
 e.g.

 def fraction(x, int=int, float=float):
 return float(x) - int(x)

 This would then read:

 def fraction(x):
 const int, float
 return float(x) - int(x)
 
 There's a certain risk that the premature-optimization fraction will
 plaster every function with const declarations, but they write
 unreadable code anyway ;)

 Aside from this, there's still another point: assume you have quite a
 number of module-level string constants which you want to use in a switch.
 You'd have to repeat all of their names in a const declaration in order
 to use them this way.

If you want to use the switch-dispatch table optimization, yes.

I'm sure we could find ways to make such declarations more
user-friendly. E.g. to declare all symbols imported from a
module constant:

# Declare the name module constant:
const module

# Declare all references module.something constant:
const module.*

This would allow you to e.g. declare all builtins constant,
avoiding cluttering up your code with const declarations,
as in the above example.

Note that such a declaration would go beyond just the use in
a switch statement. It allows you to declare names reserved
within the scope you are defining them in and gives them
a special meaning - much like global does.

Indeed, with this kind of declaration you wouldn't need to
add the switch statement to benefit from the dispatch
table optimization, since the compiler could easily identify
an if-elif-else chain as being optimizable even if it uses
symbols instead of literals for the values.

Furthermore, the compiler could do other optimizations on the
const declared names, such as optimizing away global lookups
and turning them into code object constants lookups.

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Jun 23 2006)
 Python/Zope Consulting and Support ...http://www.egenix.com/
 mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
 mxODBC, mxDateTime, mxTextTools ...http://python.egenix.com/


::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! 
___
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] Switch statement

2006-06-23 Thread Steven Bethard
[delurking in response to the first really decisive message in the thread] ;-)

On 6/22/06, Guido van Rossum [EMAIL PROTECTED] wrote:
 (1) An expression of the form 'static' atom has the semantics of
 evaluating the atom at the same time as the nearest surrounding
 function definition.

FWIW, +1.  This is clear and useful.  And code like the following
could be fixed by simply adding a static before the i, instead of
adding default arguments::

funcs = []
for i in xrange(10):
def f():
return i
funcs.append(f)

 If there is no surrounding function definition,
 'static' is a no-op and the expression is evaluated every time.
 [Alternative 1: this is an error]

+1 on the error.  Function definition time doesn't really make sense
for modules.  Only +0 on allowing only compile-time constants, since
it would be a little harder to explain.  I guess you'd want to tell
people something like think of a module as being a function that is
defined at compile time and called on import.

 (2) All case expressions in a switch have an implied 'static'.

+1.  You already have to understand that switch statements are
evaluated at function definition time, so the 'static' does seem a bit
redundant.

 (3) A switch is implemented using a dict which is precomputed at the
 same time its static expressions are precomputed. The switch
 expression must be hashable. Overlap between different cases will
 raise an exception at precomputation time.

+1.  What a wonderful, simple explanation. =)

 Independent from this, I wonder if we also need static names of the form

   static name = expression

 which would be similar to

   name = static (expression)

 but also prevents name from being assigned to elsewhere in the same scope.

-0.  I'm not sure how often this is really necessary.  I'd rather see
static expressions in Python 2.6, see how people use them, and then
decide whether or not static names are also needed.

 Also, I haven't heard a lot of thumbs up or down on the idea of using

   case X:

 to indicate a single value and

   case in S:

 to indicate a sequence of values.

+1.  This syntax seems pretty intuitive.

STeVe
-- 
I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a
tiny blip on the distant coast of sanity.
--- Bucky Katt, Get Fuzzy
___
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] Switch statement

2006-06-23 Thread M.-A. Lemburg
Reading on in the thread it seems that there's agreement
on using static instead of const, to s/const/static
:-)

M.-A. Lemburg wrote:
 Georg Brandl wrote:
 M.-A. Lemburg wrote:

 A nice side-effect would be that could easily use the
 same approach to replace the often used default-argument-hack,
 e.g.

 def fraction(x, int=int, float=float):
 return float(x) - int(x)

 This would then read:

 def fraction(x):
 const int, float
 return float(x) - int(x)
 There's a certain risk that the premature-optimization fraction will
 plaster every function with const declarations, but they write
 unreadable code anyway ;)

 Aside from this, there's still another point: assume you have quite a
 number of module-level string constants which you want to use in a switch.
 You'd have to repeat all of their names in a const declaration in order
 to use them this way.
 
 If you want to use the switch-dispatch table optimization, yes.
 
 I'm sure we could find ways to make such declarations more
 user-friendly. E.g. to declare all symbols imported from a
 module constant:
 
 # Declare the name module constant:
 const module
 
 # Declare all references module.something constant:
 const module.*
 
 This would allow you to e.g. declare all builtins constant,
 avoiding cluttering up your code with const declarations,
 as in the above example.
 
 Note that such a declaration would go beyond just the use in
 a switch statement. It allows you to declare names reserved
 within the scope you are defining them in and gives them
 a special meaning - much like global does.
 
 Indeed, with this kind of declaration you wouldn't need to
 add the switch statement to benefit from the dispatch
 table optimization, since the compiler could easily identify
 an if-elif-else chain as being optimizable even if it uses
 symbols instead of literals for the values.
 
 Furthermore, the compiler could do other optimizations on the
 const declared names, such as optimizing away global lookups
 and turning them into code object constants lookups.
 

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Jun 23 2006)
 Python/Zope Consulting and Support ...http://www.egenix.com/
 mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
 mxODBC, mxDateTime, mxTextTools ...http://python.egenix.com/


::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! 
___
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] Switch statement

2006-06-23 Thread Eric Sumner
On 6/22/06, Guido van Rossum [EMAIL PROTECTED] wrote:
 (3) A switch is implemented using a dict which is precomputed at the
 same time its static expressions are precomputed. The switch
 expression must be hashable. Overlap between different cases will
 raise an exception at precomputation time.

How does this interact with __contains__, __len__, and __iter__ for
the 'case in S' statement?  Would it work with a class that only
implements __contains__, such as a continuous range class?

  -- 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] Switch statement

2006-06-23 Thread Josiah Carlson

Guido van Rossum [EMAIL PROTECTED] wrote:
 On 6/23/06, Josiah Carlson [EMAIL PROTECTED] wrote:
  Guido van Rossum [EMAIL PROTECTED] wrote:
   Independent from this, I wonder if we also need static names of the form
  
 static name = expression
  
   which would be similar to
  
 name = static (expression)
  
   but also prevents name from being assigned to elsewhere in the same 
   scope.
 
  * I don't particularly care for the literal syntax of static.
 
 What do you mean by literal syntax of static? Do you mean 'static'
 atom or 'static'  name '=' expression? Or something else?

The existance of the static keyword and its use in general.

You later stated that decorators were the wrong way of handling it. I
believe that the...
static name = expression
...would require too many changes to what some regular python users have
come to expect from at least module namespaces.  I have nothing
constructive to say about the function local case.

I believe that static is generally fine for the...
static expression
... case, whether it is prefixed with a 'name =', or some other
operation on the value.

Allowing things like 'value  static (math.pi / 2)' brings up the
question of where the calculated value of (math.pi / 2) will be stored. 
Presumably it would be stored in a function or module const table, and
that is fine.  But what does the operation:
name = static expression
...do?  In a function namespace, do we calculate expression, assign it
to the name local on function definition and call it good?  Or do we
load the stored evaluated expression each pass through during runtime,
making it effectively equivalent to:
name = literal
I hope it's the latter (assign it to the local from a const table at the
point of the 'name = static ...' line).


  For general variables, like say; math.pi, re.DOTALL, sys.maxint, len,
  int, Exception, etc., many of them are merely references to their values,
  that is, there are no value manipulations.  This case is quite
  conveniently covered by Raymond's Decorator for BindingConstants at
  compile time, a sexy decorator available in the cookbook [1].  That
  decorator can handle all of the non-modifying value assignments, and in
  the case of Frederick's previously described:
 
 But it is an absolutely yucky approach. It modifies byte code. That
 makes it break in future Python versions (Python's byte code is not
 standardized across versions), as well in Jython, IronPython, and
 sandboxed Python (which will make a come-back, see Brett's post).

You make a good point.  It really is only usable in particular CPython
versions at any one time, though I am generally of a different opinion:
if for some desired operation X you can get identical functionality
and/or speed improvements during runtime without additional syntax, and
it is easy to use, then there is no reason to change syntax.

It seems that this particular operation can be cumbersome, is a
maintenance nightmare, and isn't applicable to non-CPython, so it
violates my reasons for 'shouldn't become syntax'.


If it makes others happy, static is fine with me.

 - 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] Switch statement

2006-06-23 Thread Phillip J. Eby
At 07:51 PM 6/23/2006 +0200, M.-A. Lemburg wrote:
Furthermore, the compiler could do other optimizations on the
const declared names, such as optimizing away global lookups
and turning them into code object constants lookups.

Technically, they'd have to become LOAD_DEREF on cells set up by the module 
level code and attached to function objects.  'marshal' won't be able to 
save function references or other such objects to a .pyc file.

It's interesting that this line of thinking does get us closer to the 
long-desired builtins optimization.  I'm envisioning:

 static __builtin__.*

or something like that.  Hm.  Maybe:

 from __builtin__ import static *

:)

In practice, however, this doesn't work for * imports unless it causes all 
global-scope names with no statically detectable assignments to become 
static.  That could be a problem for modules that generate symbols 
dynamically, like 'opcode' in the stdlib.

OTOH, maybe we could just have a LOAD_STATIC opcode that works like 
LOAD_DEREF but falls back to using globals if the cell is empty.

Interestingly, a side effect of making names static is that they also 
become private and untouchable from outside the module.

Hm.  Did I miss something, or did we just solve builtin lookup 
optimization?  The only problem I see is that currently you can stick a new 
version of 'len()' into a module from outside it, shadowing the 
builtin.  Under this scheme (of making all read-only names in a module 
become closure variables), such an assignment would change the globals, but 
have no effect on the module's behavior, which would be tied to the static 
definitions created at import time.







--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Jun 23 2006)
  Python/Zope Consulting and Support ...http://www.egenix.com/
  mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
  mxODBC, mxDateTime, mxTextTools ...http://python.egenix.com/


::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! 
___
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/pje%40telecommunity.com

___
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] Switch statement

2006-06-23 Thread Guido van Rossum
On 6/23/06, Eric Sumner [EMAIL PROTECTED] wrote:
 On 6/22/06, Guido van Rossum [EMAIL PROTECTED] wrote:
  (3) A switch is implemented using a dict which is precomputed at the
  same time its static expressions are precomputed. The switch
  expression must be hashable. Overlap between different cases will
  raise an exception at precomputation time.

 How does this interact with __contains__, __len__, and __iter__ for
 the 'case in S' statement?  Would it work with a class that only
 implements __contains__, such as a continuous range class?

No; in order to make it possible to use a single dict lookup for
dispatch, the set members are expanded into the dict key. If you have
a large contiguous range, you'll be better off (sometimes *much*
better) doing an explicit if/elif check before entering the switch.

Let me sketch a prototype for the code that builds the dict given the cases:

def build_switch(cases, globals):
  
  Args:
cases: [(op, expr, offset), ...]
  # op in ('==', 'in')
  # expr is a string giving an expression
  # offset is an integer offset where to jump for this case
globals: dict used as a namespace
  
  dispatch = {}
  for op, expr, offset in cases:
value = eval(expr, globals)
switch op:
  case '==':
if value in dispatch:
  raise RuntimeError(duplicate switch case %r == %r % (expr, value))
dispatch[value] = offset
  case 'in':
for val in value:
  if val in dispatch:
raise RuntimeError(duplicate switch case %r contains %r
% (expr, val))
  dispatch[val] = offset
  return dispatch

Of course, the real implementation would not use eval() or represent
the expressions as strings or represent all the cases as a list; the
compiler would probably generate byte code corresponding to the body
of either of the above cases for each case in the switch being
compiled. The dispatch dicts would be passed into the function object
constructor somehow. Lots of details for whoever wants to implement
this. :-)

-- 
--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] Switch statement

2006-06-23 Thread Guido van Rossum
On 6/23/06, Josiah Carlson [EMAIL PROTECTED] wrote:
 You later stated that decorators were the wrong way of handling it. I
 believe that the...
 static name = expression
 ...would require too many changes to what some regular python users have
 come to expect from at least module namespaces.  I have nothing
 constructive to say about the function local case.

It looks like static NAME = EXPR is still pretty controversial.
NAME = static EXPR seems to be getting universal +1s OTOH.

 Allowing things like 'value  static (math.pi / 2)' brings up the
 question of where the calculated value of (math.pi / 2) will be stored.
 Presumably it would be stored in a function or module const table, and
 that is fine.

A new category of data stored on the function object, computed at
function def time. It would be an array and there would be a new
opcode to load values in this array in O(1) time.

 But what does the operation:
 name = static expression
 ...do?  In a function namespace, do we calculate expression, assign it
 to the name local on function definition and call it good?

That would be impossible; the local namespace doesn't exist when the
function object is created (except for the cells used to reference
variables in outer function scopes).

 Or do we
 load the stored evaluated expression each pass through during runtime,
 making it effectively equivalent to:
 name = literal
 I hope it's the latter (assign it to the local from a const table at the
 point of the 'name = static ...' line).

Yes, the latter  should be good enough.

[On Raymond's optimizing decorator]
 You make a good point.  It really is only usable in particular CPython
 versions at any one time, though I am generally of a different opinion:
 if for some desired operation X you can get identical functionality
 and/or speed improvements during runtime without additional syntax, and
 it is easy to use, then there is no reason to change syntax.

There problem with hacks like that decorator is that if it misbehaves
(e.g. you have a global that sometimes is reassigned) you end up
debugging really hairy code. The semantics aren't 100% clear.

I'm all for telling people you can do that yourself or even here is
a standard library module that solves your problem. But the solution
needs to satisfy a certain cleanliness standard.

-- 
--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] Switch statement

2006-06-23 Thread Edward C. Jones
Python is a beautiful simple language with a rich standard library. 
Python has done fine without a switch statement up to now. Guido left it 
out of the original language for some reason (my guess is simplicity). 
Why is it needed now? What would be added next: do while or goto? The 
urge to add syntax should be resisted unless there is a high payoff 
(such as yield).

There are much better ways for the developers to spend their time and 
energy (refactoring os comes to mind).

Please keep Python simple.

-1 on the switch statement.
___
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] Switch statement

2006-06-23 Thread Guido van Rossum
On 6/23/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
 Hm.  Did I miss something, or did we just solve builtin lookup
 optimization?  The only problem I see is that currently you can stick a new
 version of 'len()' into a module from outside it, shadowing the
 builtin.  Under this scheme (of making all read-only names in a module
 become closure variables), such an assignment would change the globals, but
 have no effect on the module's behavior, which would be tied to the static
 definitions created at import time.

Or we could arrange for such assignments to be dynamically illegal. We
could have some provision whereby any name that's known to the
compiler to be a built-in, and for which the compiler can't see an
explicit assignment, is implicitly made static. This would make it a
run-time error if import * were to redefine such a name. The module
object would have to know which names are static and disallow
assignments to these. It would also have to export __dict__ as a proxy
that disallows such assignments. I think it can be made to work.

I do think this would require static names as well as static
expressions. This is definitely still in the brainstorm phase!

-- 
--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


[Python-Dev] Switch statement

2006-06-23 Thread Jim Jewett
In http://mail.python.org/pipermail/python-dev/2006-June/066399.html, PJE wrote:
 Python prefers to evaluate expressions in the order that they
 appear in source code, ... first-time use preserves that
 property; function definition time does not.

Guido wrote:
 But first-time has the very big disadvantage IMO that there's no
 safeguard to warn you that the value is different on a subsequent
 execution -- you just get the old value without warning.

That is true either way, and is already true with computed default
arguments.  The only difference is that your mental model has even
longer to become inconsistent.  (The time between definition and first
use.)

First time use also lets you use a constant (such as a dotted name
from another module) that may not yet be defined when the function is
defined, but will be defined before the function is used.

-jJ
___
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


[Python-Dev] Switch statement

2006-06-23 Thread Jim Jewett
In http://mail.python.org/pipermail/python-dev/2006-June/066409.html,
Guido wrote

 (1) An expression of the form 'static' atom has the semantics of
 evaluating the atom at the same time as the nearest surrounding
 function definition.

(A)  I prefer a term other than 'static'.

Looking at various contexts in just C, C++, and Java, I have seen
static used to imply (at least) each of private, global, singleton,
class-level, and constant.

This suggested usage sounds more like a cross between auxiliary
variable in a Lisp lambda form and compile-time defined constant.

(B)  I would prefer semantics closer to Java's final variables:  by
declaring something final, you would be promising that the next
expression can be treated as though it were a literal constant.
Python will evaluate it at least once after the final keyword but
before it gets used; anything more than that should be up to the
implementation.

The only advantage I see of specifying the time more tightly is that
people could use things that really aren't constant, iff they get the
timing right.

In http://mail.python.org/pipermail/python-dev/2006-June/066432.html,
Steven Bethard posted a fix for the I-didn't-want-a-closure problem
that uses this -- but realistically, people would still be burned by
unexpected closures just as often as they are today; the only benefit
is that the correct workaround is cleaner.

First time use has more compelling use cases, but I'm not sure they're
compelling enough.

(C)  Yes, I realize that you prefer to freeze only objects (the
results of expressions), and weren't sure about the form which also
froze the name.  But realistically, if a final name is rebound, that
is probably an error worth flagging.  I do realize that this gets into
a wider issue about how to seal a namespace.

 If there is no surrounding function definition,
 'static' is a no-op and the expression is evaluated every time.

uhm ... OK ... so why even allow it at all?  Just for consistency with
the implied static of a case statement, even though it won't mean the
same thing?

 [Alternative 1: this is an error]

OK, but ...

Things like re.DOTALL should also be final; things like
urlparse.uses_relative should not.  It seems a shame to spend a
keyword saying treat this as constant and still not be able to do so
with module-level globals.

 [Alternative 2: it is evaluated before the module is entered;
 this would imply it can not involve any imported names but it can
 involve builtins]

And parsing must take at least one more pass, and static still better
not appear inside an if statement, and ...

 [Alternative 3: precomputed the first time the switch is entered]

OK, though it will be anti-efficient compared to bailing out when you
hit a match.

Alternative 4:  computed at some point after discovering it is final,
but before using it.  For case expressions, this would be after
starting to compute the switch dictionary, but before executing
anything in the suite of this or a later alternative.

 (2) All case expressions in a switch have an implied 'static'.

Good.  But again, I would prefer that the names also be frozen, so
that people won't expect that they can change the clauses; using a
variable in a clause should be fine, but rebinding that name later
(within the same persistent scope) is at best misleading.

 (3) A switch is implemented using a dict which is precomputed at the
 same time its static expressions are precomputed. The switch
 expression must be hashable. Overlap between different cases will
 raise an exception at precomputation time.

Again, I'm not sure it makes sense to specify the time.  Any
specification will cause the following to be well-defined, but someone
will be surprised at any particular result.  My best guess is that it
your proposal would catch (A1, B1, C1, D2)

a=A1
b=B1
c=C1
d=D1
def f(v):
if sys.version_info  (2, 5, 0, , 0):
a=A2
else:
a=A3
b = static B2
c = C2
static d = D2
switch v:
case in (a, b, c, d): ...

I'm not convinced that we should forbid building the dictionary as
needed, so that it may not contain the last several cases until it
gets an input that doesn't match earlier cases.  (Though I do see the
argument for raising an Exception as early as possible if there are
conflicts.)

-jJ
___
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] Switch statement

2006-06-23 Thread Guido van Rossum
On 6/23/06, Jim Jewett [EMAIL PROTECTED] wrote:
 In http://mail.python.org/pipermail/python-dev/2006-June/066399.html, PJE 
 wrote:
  Python prefers to evaluate expressions in the order that they
  appear in source code, ... first-time use preserves that
  property; function definition time does not.

 Guido wrote:
  But first-time has the very big disadvantage IMO that there's no
  safeguard to warn you that the value is different on a subsequent
  execution -- you just get the old value without warning.

 That is true either way, and is already true with computed default
 arguments.  The only difference is that your mental model has even
 longer to become inconsistent.  (The time between definition and first
 use.)

 First time use also lets you use a constant (such as a dotted name
 from another module) that may not yet be defined when the function is
 defined, but will be defined before the function is used.

I should probably just pronounce on this; I'm not going to change my
mind, so def-time-freeze it is (if we do this at all). Ditto for
static inside a function (if we do that at all). Static and switch
outside a function are still somewhat open; I'm currently leaning
towards making static expressions outside a function illegal and limit
switches outside a function to compile-time-constant expressions.

Here are a few examples showing my objections against first-use.

def foo(c):
  def bar(x):
switch x:
case c: print 42
else: print 0
  return bar

p = foo(1)
p(1)  # prints 42
q = foo(2)
q(2)  # does this print 42 or 0?

I think q(2) should print 42; otherwise it's not clear what object
should be used to hold the frozen switch dict; it can't be the code
object since code objects need to be immutable and cannot have any
variable state.

But then the def time enters into it anyway...

Another example is this:

def foo(c, x):
  switch x:
  case c: print 42
  else: print 0

Should this be allowed? The first-use rule has no strong motivation to
forbid it, since *knowing* the first-rule it's reasonable to expect
that *any* case expression will just be evalluated in the local scope
at the first use of the switch. But it's just begging for confusion if
the reader isn't clued in to the first-use rule. The def-time rule
simply forbids this; any switch you're likely to write with the
def-time rule is almost certain to use only global and imported
variables that are constants in the user's mind.

With the def-time rule, you'd have to work a lot harder to construct
an example that works differently than the casual reader would expect.

-- 
--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] Switch statement

2006-06-23 Thread Guido van Rossum
This post is too long for me to respond right now. I'm inviting others
to respond. I've got a feeling you're coming late to this discussion
and we're going around in circles.

--Guido

On 6/23/06, Jim Jewett [EMAIL PROTECTED] wrote:
 In http://mail.python.org/pipermail/python-dev/2006-June/066409.html,
 Guido wrote

  (1) An expression of the form 'static' atom has the semantics of
  evaluating the atom at the same time as the nearest surrounding
  function definition.

 (A)  I prefer a term other than 'static'.

 Looking at various contexts in just C, C++, and Java, I have seen
 static used to imply (at least) each of private, global, singleton,
 class-level, and constant.

 This suggested usage sounds more like a cross between auxiliary
 variable in a Lisp lambda form and compile-time defined constant.

 (B)  I would prefer semantics closer to Java's final variables:  by
 declaring something final, you would be promising that the next
 expression can be treated as though it were a literal constant.
 Python will evaluate it at least once after the final keyword but
 before it gets used; anything more than that should be up to the
 implementation.

 The only advantage I see of specifying the time more tightly is that
 people could use things that really aren't constant, iff they get the
 timing right.

 In http://mail.python.org/pipermail/python-dev/2006-June/066432.html,
 Steven Bethard posted a fix for the I-didn't-want-a-closure problem
 that uses this -- but realistically, people would still be burned by
 unexpected closures just as often as they are today; the only benefit
 is that the correct workaround is cleaner.

 First time use has more compelling use cases, but I'm not sure they're
 compelling enough.

 (C)  Yes, I realize that you prefer to freeze only objects (the
 results of expressions), and weren't sure about the form which also
 froze the name.  But realistically, if a final name is rebound, that
 is probably an error worth flagging.  I do realize that this gets into
 a wider issue about how to seal a namespace.

  If there is no surrounding function definition,
  'static' is a no-op and the expression is evaluated every time.

 uhm ... OK ... so why even allow it at all?  Just for consistency with
 the implied static of a case statement, even though it won't mean the
 same thing?

  [Alternative 1: this is an error]

 OK, but ...

 Things like re.DOTALL should also be final; things like
 urlparse.uses_relative should not.  It seems a shame to spend a
 keyword saying treat this as constant and still not be able to do so
 with module-level globals.

  [Alternative 2: it is evaluated before the module is entered;
  this would imply it can not involve any imported names but it can
  involve builtins]

 And parsing must take at least one more pass, and static still better
 not appear inside an if statement, and ...

  [Alternative 3: precomputed the first time the switch is entered]

 OK, though it will be anti-efficient compared to bailing out when you
 hit a match.

 Alternative 4:  computed at some point after discovering it is final,
 but before using it.  For case expressions, this would be after
 starting to compute the switch dictionary, but before executing
 anything in the suite of this or a later alternative.

  (2) All case expressions in a switch have an implied 'static'.

 Good.  But again, I would prefer that the names also be frozen, so
 that people won't expect that they can change the clauses; using a
 variable in a clause should be fine, but rebinding that name later
 (within the same persistent scope) is at best misleading.

  (3) A switch is implemented using a dict which is precomputed at the
  same time its static expressions are precomputed. The switch
  expression must be hashable. Overlap between different cases will
  raise an exception at precomputation time.

 Again, I'm not sure it makes sense to specify the time.  Any
 specification will cause the following to be well-defined, but someone
 will be surprised at any particular result.  My best guess is that it
 your proposal would catch (A1, B1, C1, D2)

 a=A1
 b=B1
 c=C1
 d=D1
 def f(v):
 if sys.version_info  (2, 5, 0, , 0):
 a=A2
 else:
 a=A3
 b = static B2
 c = C2
 static d = D2
 switch v:
 case in (a, b, c, d): ...

 I'm not convinced that we should forbid building the dictionary as
 needed, so that it may not contain the last several cases until it
 gets an input that doesn't match earlier cases.  (Though I do see the
 argument for raising an Exception as early as possible if there are
 conflicts.)

 -jJ
 ___
 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/)

Re: [Python-Dev] Switch statement

2006-06-23 Thread Bryan O'Sullivan
On Fri, 2006-06-23 at 16:16 -0400, Edward C. Jones wrote:

 Please keep Python simple.

+1 on this sentiment.

I use switch statements all the time in C, but I'd rather not see them
in Python - even though I'd use them if they were there! - purely to
keep the cognitive overhead low.

b

___
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] Switch statement

2006-06-23 Thread Jim Jewett
On 6/23/06, Guido van Rossum [EMAIL PROTECTED] wrote:
 Here are a few examples showing my objections against first-use.

[Problem with nested scopes; today this usually shows up as (invalid)
bug reports about lambda, in which failure to bind a default
variable to itself causes it to take on the value at the end of the
loop, instead of the value of the index when defined.]

[Problem with using a parameter as a case selector -- at least these
aren't available at definition time.]

 With the def-time rule, you'd have to work a lot harder to construct
 an example that works differently than the casual reader would expect.

Anything which use the same names in the local scope, particularly if
those names are themselves marked final (or static).

a=1
b=2
c=3
def f(v):
a=4# This gets ignored?
final b=5# But what about this?  It is local, but a
constant known in advance
switch v:
case in (a, b, c): ...
final c=6# Also a constant, but textually after the case keyword.

-jJ
___
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] Switch statement

2006-06-23 Thread Eric Sumner
On 6/23/06, Guido van Rossum [EMAIL PROTECTED] wrote:
 No; in order to make it possible to use a single dict lookup for
 dispatch, the set members are expanded into the dict key. If you have
 a large contiguous range, you'll be better off (sometimes *much*
 better) doing an explicit if/elif check before entering the switch.

In that case, I would argue that the proposed syntax is misleading.
Regardless of how it is implemented, a switch statement is
conceptually a chain of if/elif statements.  As such, the 'in'
keyword, if it is allowed at all, should behave like it does in if
statements, rather than it does in loops.  If, for implementation
reasons, you want to ensure that all of the sets are enumerable, I
would recommend a syntax like this:

   case [*] expression (, [*] expression)* : suite

This is consistent with parameter lists, which emphasizes that the
sequences are being enumerated instead of simply tested against.

  -- 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] Switch statement

2006-06-23 Thread Jean-Paul Calderone
On Fri, 23 Jun 2006 13:38:35 -0700, Bryan O'Sullivan [EMAIL PROTECTED] wrote:
On Fri, 2006-06-23 at 16:16 -0400, Edward C. Jones wrote:

 Please keep Python simple.

+1 on this sentiment.


I agree.

Jean-Paul
___
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] Switch statement

2006-06-23 Thread Josiah Carlson

Eric Sumner [EMAIL PROTECTED] wrote:
 
 On 6/23/06, Guido van Rossum [EMAIL PROTECTED] wrote:
  No; in order to make it possible to use a single dict lookup for
  dispatch, the set members are expanded into the dict key. If you have
  a large contiguous range, you'll be better off (sometimes *much*
  better) doing an explicit if/elif check before entering the switch.
 
 In that case, I would argue that the proposed syntax is misleading.
 Regardless of how it is implemented, a switch statement is
 conceptually a chain of if/elif statements.  As such, the 'in'
 keyword, if it is allowed at all, should behave like it does in if
 statements, rather than it does in loops.  If, for implementation
 reasons, you want to ensure that all of the sets are enumerable, I
 would recommend a syntax like this:
 
case [*] expression (, [*] expression)* : suite
 
 This is consistent with parameter lists, which emphasizes that the
 sequences are being enumerated instead of simply tested against.

You apparently missed the post where Guido expressed that he believes
that one of the valid motivators for the switch statement and the
dict-based dispatching was for that of speed improvements.  He also
already stated that cases could essentially only be examples for which
Python does pre-computation and the storing of constants (he didn't use
those words, and there are caveats with regards to module.attr and
global 'constants', but that was the gist I got from it).

As such, because any explicit range object is neither dict-accessable as
the values in the range would be, nor are they generally precomputed (or
precomputable) as constants (like (1,2,3) is and 1+1 should be), your
particular use-case (range objects that may implement __contains__ fast,
but whose __iter__ returns a huge number of values if it were
implemented as such) is not covered under switch/case, and we would
likely point you back off to if/elif/else.

This is a good thing, because if switch/case ends up functionally
identical to if/elif/else, then it has no purpose as a construct.  On
the other hand, because it is different from if/elif/else, and it is
different in such a way to make certain blocks of code (arguably) easier
to read or understand, (likely provably) faster, then it actually has a
purpose and use.


 - 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] Switch statement

2006-06-23 Thread Guido van Rossum
On 6/23/06, Josiah Carlson [EMAIL PROTECTED] wrote:
 This is a good thing, because if switch/case ends up functionally
 identical to if/elif/else, then it has no purpose as a construct.  On
 the other hand, because it is different from if/elif/else, and it is
 different in such a way to make certain blocks of code (arguably) easier
 to read or understand, (likely provably) faster, then it actually has a
 purpose and use.

Excellent formulation!

-- 
--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] Switch statement

2006-06-23 Thread James Y Knight

On Jun 22, 2006, at 3:24 PM, Phillip J. Eby wrote:

 Well, you can't def a dotted name, but I realize this isn't a  
 binding.

I have actually wanted to do that before. It would be nice if you  
could. :)

James
___
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] Switch statement

2006-06-23 Thread Eric Sumner
  In that case, I would argue that the proposed syntax is misleading.
  Regardless of how it is implemented, a switch statement is
  conceptually a chain of if/elif statements.  As such, the 'in'
  keyword, if it is allowed at all, should behave like it does in if
  statements, rather than it does in loops.  If, for implementation
  reasons, you want to ensure that all of the sets are enumerable, I
  would recommend a syntax like this:
 
 case [*] expression (, [*] expression)* : suite
 
  This is consistent with parameter lists, which emphasizes that the
  sequences are being enumerated instead of simply tested against.

 You apparently missed the post where Guido expressed that he believes
 that one of the valid motivators for the switch statement and the
 dict-based dispatching was for that of speed improvements.  He also
 already stated that cases could essentially only be examples for which
 Python does pre-computation and the storing of constants (he didn't use
 those words, and there are caveats with regards to module.attr and
 global 'constants', but that was the gist I got from it).

I admit that I came into this discussion in the middle, and my initial
post was for informational (to me) purposes only.  I did not mean to
imply by that post that the proposal was flawed in any way, just to
verify that I properly understood the proposal.  I am sorry if I was
unclear about this.

 As such, because any explicit range object is neither dict-accessable as
 the values in the range would be, nor are they generally precomputed (or
 precomputable) as constants (like (1,2,3) is and 1+1 should be), your
 particular use-case (range objects that may implement __contains__ fast,
 but whose __iter__ returns a huge number of values if it were
 implemented as such) is not covered under switch/case, and we would
 likely point you back off to if/elif/else.

I concur.  I actually suspected as much prior to my original message
on this topic, but I wanted to make sure I was understanding things
correctly before attempting to make a suggestion.

 This is a good thing, because if switch/case ends up functionally
 identical to if/elif/else, then it has no purpose as a construct.  On
 the other hand, because it is different from if/elif/else, and it is
 different in such a way to make certain blocks of code (arguably) easier
 to read or understand, (likely provably) faster, then it actually has a
 purpose and use.

Again, I concur.  My point was not that the mechanics of the construct
were incorrect, but that the proposed syntax misrepresented its
function.  Again, I am sorry if I was unclear about this.

  -- 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] Switch statement

2006-06-23 Thread Talin
Guido van Rossum wrote:

 That sounds like a good solution all around. I hope that others can
 also find themselves in this.
 
 (1) An expression of the form 'static' atom has the semantics of
 evaluating the atom at the same time as the nearest surrounding
 function definition. If there is no surrounding function definition,
 'static' is a no-op and the expression is evaluated every time.
 [Alternative 1: this is an error] [Alternative 2: it is evaluated
 before the module is entered; this would imply it can not involve any
 imported names but it can involve builtins] [Alternative 3:
 precomputed the first time the switch is entered]

I'm thinking that outside of a function, 'static' just means that the 
expression is evaluated at compile-time, with whatever symbols the 
compiler has access to (including any previously-defined statics in that 
module). The result of the expression is then inserted into the module 
code just like any literal.

So for example:

a = static len( 1234 )

compiles as:

a = 4

...assuming that you can call 'len' at compile time.

The rationale here is that I'm trying to create an analogy between 
functions and modules, where the 'static' declaration has an analogous 
relationship to a module as it does to a function. Since a module is 
'defined' when its code is compiled, that would be when the evaluation 
occurs.

I'm tempted to propose a way for the compiler to import static 
definitions from outside the module ('static import'?) however I 
recognize that this would greatly increase the fragility of Python, 
since now you have the possibility that a module could be compiled with 
a set of numeric constants that are out of date with respect to some 
other module.

-- 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] Switch statement

2006-06-23 Thread Nick Coghlan
Guido van Rossum wrote:
 On 6/22/06, Nick Coghlan [EMAIL PROTECTED] wrote:
 Talin wrote:
  I don't get what the problem is here. A switch constant should have
  exactly the bahavior of a default value of a function parameter. We
  don't seem to have too many problems defining functions at the module
  level, do we?

 Because in function definitions, if you put them inside another 
 function, the
 defaults of the inner function get reevaluated every time the outer 
 function
 is run. Doing that for the switch statement would kinda defeat the whole
 point. . .
 
 Really? Then where would you store the dict? You can't store it on the
 code object because that's immutable. You can't store it on the
 function object (if you don't want it to be re-evaluated when the
 function is redefined) because a new function object is created by
 each redefinition. There needs to be *some* kind of object with a
 well-defined life cycle where to store the dict.
 
 I'd say that we should just add a warning against switches in nested
 functions that are called only once per definition.

I wasn't very clear. . .

Talin noted that there's no ambiguity with the timing of the evaluation of 
default function arguments, regardless of whether the function definition is 
at module scope or inside another function - the default arguments are simply 
evaluated every time the function definition is executed. So he wondered why 
that simplicity didn't translate to the evaluation of switch cases.

With a switch statement, we want the cases evaluated when the *containing* def 
statement is executed, not every time the switch statement itself is executed. 
Which makes things far more complex :)

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] Switch statement

2006-06-22 Thread Greg Ewing
Fredrik Lundh wrote:
  Q: If a program calls the 'func' function below as 'func()'
 and ONE and TWO are both integer objects, what does 'func'
   ^^
Nothing at all, because you didn't call it!

--
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] Switch statement

2006-06-22 Thread Roger Miller
Ka-Ping Yee wrote:
  Hmm, this is rather nice.  I can imagine possible use cases for
 
 switch x:
 case  3: foo(x)
 case is y: spam(x)
 case == z: eggs(x)

Part of the readability advantage of a switch over an if/elif chain is 
the semantic parallelism, which would make me question mixing different 
tests in the same switch.  What if the operator moved into the switch 
header?

 switch x ==:
 case 1: foo(x)
case 2, 3: bar(x)

 switch x in:
case (1, 3, 5): do_odd(x)
case (2, 4, 6): do_even(x)

switch x: could be equivalent to switch x ==:, for the common case.

I've also been wondering whether the 'case' keyword is really necessary? 
  Would any ambiguities or other parsing problems arise if you wrote:

 switch x:
 1: foo(x)
2: bar(x)

It is debatable whether this is more or less readable, but it seemed 
like an interesting question for the language lawyers.
___
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] Switch statement

2006-06-22 Thread Greg Ewing
Phillip J. Eby wrote:

  switch x:
  case == 1: foo(x)

Aesthetically, I don't like that.

--
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] Switch statement

2006-06-22 Thread Nick Coghlan
Talin wrote:
 I don't get what the problem is here. A switch constant should have 
 exactly the bahavior of a default value of a function parameter. We 
 don't seem to have too many problems defining functions at the module 
 level, do we?

Because in function definitions, if you put them inside another function, the 
defaults of the inner function get reevaluated every time the outer function 
is run. Doing that for the switch statement would kinda defeat the whole 
point. . .

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] Switch statement

2006-06-22 Thread M.-A. Lemburg
Phillip J. Eby wrote:
 Maybe the real answer is to have a const declaration, not necessarily the 
 way that Fredrik suggested, but a way to pre-declare constants e.g.:
 
  const FOO = 27
 
 And then require case expressions to be either literals or constants.  The 
 constants need not be computable at compile time, just runtime.  If a 
 constant is defined using a foldable expression (e.g. FOO = 27 + 43), then 
 the compiler can always optimize it down to a code level 
 constant.  Otherwise, it can just put constants into cells that the 
 functions use as part of their closure.  (For that matter, the switch 
 statement jump tables, if any, can be put in a cell too.)
 
 I don't like first use because it seems to invite tricks.
 
 Okay, then I think we need a way to declare a global as being constant.  It 
 seems like all the big problems with switch/case basically amount to us 
 trying to wiggle around the need to explicitly declare constants.

I don't think that this would help us much:

If you want the compiler to see that a name binds to a constant,
it would need to have access to the actual value at compile time
(e.g. code object definition time).

However, it is common practice to put constants which you'd use
in e.g. parsers into a separate module and you certainly don't
want to have the compiler import the module and apply attribute
lookups.

This means that you'd have to declare a symbol constant in the
scope where you want to use it as such. Which would result in
long sections of e.g.

const case1
const case2
...
const caseN

In the end, making this implicit in the case part of the switch
statement would save us a lot of typing.

However, there's another catch: if we do allow arbitrary expressions
in the case parts we still need to evaluate them at some point:

a. If we do so at compile time, the results may be a lot different
than at execution time (e.g. say you use time.time() in one of the
case value expressions).

b. If we evaluate them at code object execution time (e.g. module
import), then we'd run into similar problems, but at least
the compiler wouldn't have to have access to the used symbols.

c. If we evaluate at first-use time, results of the evaluation
become unpredictable and you'd also lose a lot of the
speedup since building the hash table would consume cycles
that you'd rather spend on doing other things.

d. Ideally, you'd want to create the hash table at compile time
and this is only possible using literals or by telling the
compiler to regard a specific set of globals as constant, e.g.
by passing a dictionary (mapping globals to values) to compile().

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Jun 22 2006)
 Python/Zope Consulting and Support ...http://www.egenix.com/
 mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
 mxODBC, mxDateTime, mxTextTools ...http://python.egenix.com/

2006-07-03: EuroPython 2006, CERN, Switzerland  10 days left

::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! 
___
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] Switch statement

2006-06-22 Thread Phillip J. Eby
At 01:08 PM 6/22/2006 +0200, M.-A. Lemburg wrote:
Phillip J. Eby wrote:
  Maybe the real answer is to have a const declaration, not necessarily 
 the
  way that Fredrik suggested, but a way to pre-declare constants e.g.:
 
   const FOO = 27
 
  And then require case expressions to be either literals or constants.  The
  constants need not be computable at compile time, just runtime.  If a
  constant is defined using a foldable expression (e.g. FOO = 27 + 43), then
  the compiler can always optimize it down to a code level
  constant.  Otherwise, it can just put constants into cells that the
  functions use as part of their closure.  (For that matter, the switch
  statement jump tables, if any, can be put in a cell too.)
 
  I don't like first use because it seems to invite tricks.
 
  Okay, then I think we need a way to declare a global as being 
 constant.  It
  seems like all the big problems with switch/case basically amount to us
  trying to wiggle around the need to explicitly declare constants.

I don't think that this would help us much:

If you want the compiler to see that a name binds to a constant,
it would need to have access to the actual value at compile time
(e.g. code object definition time).

No, it wouldn't.  This hypothetical const would be a *statement*, 
executed like any other statement.  It binds a name to a value -- and 
produces an error if the value changes.  The compiler doesn't need to know 
what it evaluates to at runtime; that's what LOAD_NAME or LOAD_DEREF are 
for.  ;)


However, it is common practice to put constants which you'd use
in e.g. parsers into a separate module and you certainly don't
want to have the compiler import the module and apply attribute
lookups.

Not necessary, but I see it does produce a different problem.


This means that you'd have to declare a symbol constant in the
scope where you want to use it as such. Which would result in
long sections of e.g.

const case1
const case2
...
const caseN

Actually, under my proposal it'd be:

const FOO = somemodule.FOO
const BAR = somemodule.BAR

etc.  Which is probably actually worse.  But I see your point.


In the end, making this implicit in the case part of the switch
statement would save us a lot of typing.

However, there's another catch: if we do allow arbitrary expressions
in the case parts we still need to evaluate them at some point:

a. If we do so at compile time, the results may be a lot different
than at execution time (e.g. say you use time.time() in one of the
case value expressions).

We can't do that at compile time.

b. If we evaluate them at code object execution time (e.g. module
import), then we'd run into similar problems, but at least
the compiler wouldn't have to have access to the used symbols.

c. If we evaluate at first-use time, results of the evaluation
become unpredictable and you'd also lose a lot of the
speedup since building the hash table would consume cycles
that you'd rather spend on doing other things.

Assuming that a sequential search takes 1/2N equality tests on average, 
you'll come out ahead by the third switch executions, assuming that the 
time to add a dictionary entry or do a hash lookup is roughly equal to an 
if/else test.  The first execution would put N entries in the dictionary, 
and do 1 lookup.  The second execution does 1 lookup, so we're now at N+2 
operations, vs N operations on average for sequential search.  At the third 
execution, we're at N+3 vs. 2.5N, so for more than 6 entries we're already 
ahead.


d. Ideally, you'd want to create the hash table at compile time
and this is only possible using literals or by telling the
compiler to regard a specific set of globals as constant, e.g.
by passing a dictionary (mapping globals to values) to compile().

I still think that it suffices to assume that an expression produced using 
only symbols that aren't rebound are sufficiently static for use in a case 
expression.  If a symbol is bound by a single import statement (or other 
definition), or isn't bound at all (e.g. it's a builtin), it's easy enough 
to assume that it's going to remain the same.

Combine that compile-time restriction with a first-use build of the 
dictionary, and I think you have the best that we can hope to do in 
balancing implementation simplicity with usefulness and 
non-confusingness.  If it's not good enough, it's not good enough, but I 
don't think there's anything we've thought of so far that comes out with a 
better set of tradeoffs.

___
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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Roger Miller [EMAIL PROTECTED] wrote:
 Part of the readability advantage of a switch over an if/elif chain is
 the semantic parallelism, which would make me question mixing different
 tests in the same switch.  What if the operator moved into the switch
 header?

  switch x ==:
  case 1: foo(x)
 case 2, 3: bar(x)

  switch x in:
 case (1, 3, 5): do_odd(x)
 case (2, 4, 6): do_even(x)

 switch x: could be equivalent to switch x ==:, for the common case.

That's difficult (I mean impossible) for Python's parser, since x ==
is also the legal start of an expression.

 I've also been wondering whether the 'case' keyword is really necessary?
   Would any ambiguities or other parsing problems arise if you wrote:

  switch x:
  1: foo(x)
 2: bar(x)

 It is debatable whether this is more or less readable, but it seemed
 like an interesting question for the language lawyers.

That's no problem for the parser, as long as the expressions are
indented. ABC did this.

But I think I like an explicit case keyword better; it gives a better
error message if the indentation is forgotten.

-- 
--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] Switch statement

2006-06-22 Thread Georg Brandl
Guido van Rossum wrote:

 I've also been wondering whether the 'case' keyword is really necessary?
   Would any ambiguities or other parsing problems arise if you wrote:

  switch x:
  1: foo(x)
 2: bar(x)

 It is debatable whether this is more or less readable, but it seemed
 like an interesting question for the language lawyers.
 
 That's no problem for the parser, as long as the expressions are
 indented. ABC did this.
 
 But I think I like an explicit case keyword better; it gives a better
 error message if the indentation is forgotten.

It also overthrows the notion that suites are started by statements, not
by expressions.

Georg

___
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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/21/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
 At 01:16 PM 6/21/2006 -0700, Guido van Rossum wrote:
 Yeah, but if you have names for your constants it would be a shame if
 you couldn't use them because they happen to be defined in the same
 scope.

 Maybe the real answer is to have a const declaration, not necessarily the
 way that Fredrik suggested, but a way to pre-declare constants e.g.:

  const FOO = 27

The problem with this is that I don't see how to export this property
from one module to another. If module A has the above statement and
module B does from A import FOO then how does the parser know that
FOO is a constant when it's parsing B? (Remeber the parser only sees
one module at a time; I don't want to drop this separate compilation
facility.) It seems you would still end up with lots of duplicate
const declarations (e.g. from A import const FOO). And it should
also be possible to say import A and then use A.FOO as a constant.

I really don't think this ad-hoc solution is going to work.

 And then require case expressions to be either literals or constants.  The
 constants need not be computable at compile time, just runtime.  If a
 constant is defined using a foldable expression (e.g. FOO = 27 + 43), then
 the compiler can always optimize it down to a code level
 constant.  Otherwise, it can just put constants into cells that the
 functions use as part of their closure.  (For that matter, the switch
 statement jump tables, if any, can be put in a cell too.)

 I don't like first use because it seems to invite tricks.

 Okay, then I think we need a way to declare a global as being constant.  It
 seems like all the big problems with switch/case basically amount to us
 trying to wiggle around the need to explicitly declare constants.

And I don't believe declaring constants is going to work; not without
a much bigger change to the language and the way we think about it.
This is because const-ness isn't a property that you can encode as a
new type of object. It is a compile-time property of *names*. The only
similar thing in Python is globals. But global declarations are
intentionally a bit clunky because we believe overuse of the feature
would be a mistake. But we wouldn't want to discourage constant
declaration if we had them, so having to repeat the 'constant' keyword
in every module that uses a particular constant would be a painful
wart.

Is your objection purely based on the problems of getting switch to
behave the same way inside and outside a function? I'd rather forbid
or cripple switch outside functions than either add constant
declarations or switch to first-use semantics.

-- 
--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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Greg Ewing [EMAIL PROTECTED] wrote:
 Phillip J. Eby wrote:

   switch x:
   case == 1: foo(x)

 Aesthetically, I don't like that.

Me neither.

-- 
--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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Nick Coghlan [EMAIL PROTECTED] wrote:
 Talin wrote:
  I don't get what the problem is here. A switch constant should have
  exactly the bahavior of a default value of a function parameter. We
  don't seem to have too many problems defining functions at the module
  level, do we?

 Because in function definitions, if you put them inside another function, the
 defaults of the inner function get reevaluated every time the outer function
 is run. Doing that for the switch statement would kinda defeat the whole
 point. . .

Really? Then where would you store the dict? You can't store it on the
code object because that's immutable. You can't store it on the
function object (if you don't want it to be re-evaluated when the
function is redefined) because a new function object is created by
each redefinition. There needs to be *some* kind of object with a
well-defined life cycle where to store the dict.

I'd say that we should just add a warning against switches in nested
functions that are called only once per definition.

-- 
--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] Switch statement

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

 which simply means that expr will be evaluated at function definition
 time, rather than at runtime.  example usage:

  var = expression
  if var == constant sre.FOO:
  ...
  elif var == constant sre.BAR:
  ...
  elif var in constant (sre.FIE, sre.FUM):
  ...
 
 This gets pretty repetitive. One might suggest that 'case' could imply
 'constant'...?

possibly, but I find that a tad too magic for my taste.

a constant (or perhaps better, const) primary would also be useful 
in several other cases, including:

- as a replacement for default-argument object binding

- local dispatch tables, and other generated-but-static data structures

- explicit (but still anonymous) constant/expression folding

an alternative would be to add a const declaration that can only be used 
in local scopes; i.e.

 def foo(value):
const bar = fie.fum
if value == bar:
   ...

which would behave like

 def foo(value, bar=fie.fum):
if value == bar:
...

but without the what if we pass in more than one argument? issue.

yet another alternative would be a const declaration that you could use 
on a global level, but I fail to see how you could propagate the const- 
ness property to whoever wants to use a const object -- unless, of 
course, you implement

 const bar = fie.fum

 def foo(value):
if value == bar:
   ...

as

 class constant_wrapper(object):
 def __init__(self, value):
 self.value = value

 bar = constant_wrapper(fie.fum)

 def foo(value, bar=bar.value):
 if value == bar:
 ...

(except for the default argument thing; see above).  the result is a 
kind of semi-constant objects that would be useful, but perhaps not 
constant enough...)

it might be too much C# exposure, but I think I prefer the explicit 
when using approach...

/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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
 This hypothetical const would be a *statement*,
 executed like any other statement.  It binds a name to a value -- and
 produces an error if the value changes.  The compiler doesn't need to know
 what it evaluates to at runtime; that's what LOAD_NAME or LOAD_DEREF are
 for.  ;)

Please think this through more. How do you implement the produces an
error if the value changes part? Is the const property you're
thinking of part of the name or of the object it refers to?

The only way I can see it work is if const-ness is a compile-time
property of names, just like global. But that requires too much
repetition when a constant is imported.

-- 
--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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Fredrik Lundh [EMAIL PROTECTED] wrote:
 a constant (or perhaps better, const) primary would also be useful
 in several other cases, including:

 - as a replacement for default-argument object binding

 - local dispatch tables, and other generated-but-static data structures

 - explicit (but still anonymous) constant/expression folding

 an alternative would be to add a const declaration that can only be used
 in local scopes; i.e.

  def foo(value):
 const bar = fie.fum
 if value == bar:
...

 which would behave like

  def foo(value, bar=fie.fum):
 if value == bar:
 ...

 but without the what if we pass in more than one argument? issue.

So the constant would be evaluated at function definition time? I find
that rather confusing. Especially since common uses will probably
include

  const true = True
  while true:
...code...

This is a well-meaning attempt to let the compiler optimize this to a
test-less infinite loop that works but throws the baby out with the
bathwater.

 yet another alternative would be a const declaration that you could use
 on a global level, but I fail to see how you could propagate the const-
 ness property to whoever wants to use a const object -- unless, of
 course, you implement

  const bar = fie.fum

  def foo(value):
 if value == bar:
...

 as

  class constant_wrapper(object):
  def __init__(self, value):
  self.value = value

  bar = constant_wrapper(fie.fum)

  def foo(value, bar=bar.value):
  if value == bar:
  ...

 (except for the default argument thing; see above).  the result is a
 kind of semi-constant objects that would be useful, but perhaps not
 constant enough...)

I fail to see the usefulness of this wrapper. The wrapper isn't
completely transparent o some code that uses type checks may need to
be modified. The wrapper doesn't get removed by a simple assignment;
after

  const a = 1
  b = a

how do we prevent b from being treated as a constant?

 it might be too much C# exposure, but I think I prefer the explicit
 when using approach...

It may be not enough C# exposure, but I don't know exactly which
approach you are referring to.

-- 
--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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Georg Brandl [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:

  I've also been wondering whether the 'case' keyword is really necessary?
Would any ambiguities or other parsing problems arise if you wrote:
 
   switch x:
   1: foo(x)
  2: bar(x)
 
  It is debatable whether this is more or less readable, but it seemed
  like an interesting question for the language lawyers.
 
  That's no problem for the parser, as long as the expressions are
  indented. ABC did this.
 
  But I think I like an explicit case keyword better; it gives a better
  error message if the indentation is forgotten.

 It also overthrows the notion that suites are started by statements, not
 by expressions.

I'm not sure I care about that. Do you use this in teaching? How does
it help you?

-- 
--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] Switch statement

2006-06-22 Thread Georg Brandl
Guido van Rossum wrote:
 On 6/22/06, Georg Brandl [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:

  I've also been wondering whether the 'case' keyword is really necessary?
Would any ambiguities or other parsing problems arise if you wrote:
 
   switch x:
   1: foo(x)
  2: bar(x)
 
  It is debatable whether this is more or less readable, but it seemed
  like an interesting question for the language lawyers.
 
  That's no problem for the parser, as long as the expressions are
  indented. ABC did this.
 
  But I think I like an explicit case keyword better; it gives a better
  error message if the indentation is forgotten.

 It also overthrows the notion that suites are started by statements, not
 by expressions.
 
 I'm not sure I care about that. Do you use this in teaching? How does
 it help you?

I just realized that my post could be misunderstood: The sentence referred
to the case-less form. (And it's just a feeling thing)

Georg

___
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] Switch statement

2006-06-22 Thread Phillip J. Eby
At 09:37 AM 6/22/2006 -0700, Guido van Rossum wrote:
On 6/22/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
  This hypothetical const would be a *statement*,
  executed like any other statement.  It binds a name to a value -- and
  produces an error if the value changes.  The compiler doesn't need to know
  what it evaluates to at runtime; that's what LOAD_NAME or LOAD_DEREF are
  for.  ;)

Please think this through more. How do you implement the produces an
error if the value changes part? Is the const property you're
thinking of part of the name or of the object it refers to?

The only way I can see it work is if const-ness is a compile-time
property of names, just like global. But that requires too much
repetition when a constant is imported.

Right; MAL pointed that out in the message I was replying to, and I 
conceded his point.  Of course, if you consider constness to be an implicit 
property of imported names that aren't rebound, the repetition problem goes 
away.

And if you then require all case expressions to be either literals or 
constant names, we can also duck the when does the expression get 
evaluated? question.  The obvious answer is that it's evaluated wherever 
you bound the name, and the compiler can either optimize the switch 
statement (or not), depending on where the assignment took place.  A switch 
that's in a loop or a function call can only be optimized if all its 
constants are declared outside the loop or function body; otherwise it 
degrades to an if/elif chain.

There's actually an in-between possibility, too: you could generate if's 
for constants declared in the loop or function body, and use a dictionary 
for any literals or constants declared outside the loop or function 
body.  The only problem that raises is the possibility of an inner 
constant being equal to an outer constant, creating an ambiguity.  But 
we could just say that nearer constants take precedence over later ones, or 
force you to introduce the cases such that inner constants appear first.

(This approach doesn't really need an explicit const foo=bar declaration, 
though; it just restricts cases to using names that are bound only once in 
the code of the scope they're obtained from.)

___
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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Georg Brandl [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  On 6/22/06, Georg Brandl [EMAIL PROTECTED] wrote:
  Guido van Rossum wrote:
 
   I've also been wondering whether the 'case' keyword is really necessary?
 Would any ambiguities or other parsing problems arise if you wrote:
  
switch x:
1: foo(x)
   2: bar(x)
  
   It is debatable whether this is more or less readable, but it seemed
   like an interesting question for the language lawyers.
  
   That's no problem for the parser, as long as the expressions are
   indented. ABC did this.
  
   But I think I like an explicit case keyword better; it gives a better
   error message if the indentation is forgotten.
 
  It also overthrows the notion that suites are started by statements, not
  by expressions.
 
  I'm not sure I care about that. Do you use this in teaching? How does
  it help you?

 I just realized that my post could be misunderstood: The sentence referred
 to the case-less form. (And it's just a feeling thing)

I understood that. And I don't have the same feeling. :-)

-- 
--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] Switch statement

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

  def foo(value):
 const bar = fie.fum
 if value == bar:
...

 which would behave like

  def foo(value, bar=fie.fum):
 if value == bar:
 ...

 but without the what if we pass in more than one argument? issue.
 
 So the constant would be evaluated at function definition time? I find
 that rather confusing.

well, I find the proposed magic behaviour of case at least as confusing...

 (except for the default argument thing; see above).  the result is a
 kind of semi-constant objects that would be useful, but perhaps not
 constant enough...)
 
 I fail to see the usefulness of this wrapper. The wrapper isn't
 completely transparent o some code that uses type checks may need to
 be modified. The wrapper doesn't get removed by a simple assignment;
 after
 
   const a = 1
   b = a
 
 how do we prevent b from being treated as a constant?

we cannot -- this approaches assigns (a small amount of) const-ness to 
objects, not names.

 it might be too much C# exposure, but I think I prefer the explicit
 when using approach...
 
 It may be not enough C# exposure, but I don't know exactly which
 approach you are referring to.

the original one: if you want to treat an expression as a constant, you 
have to be explicit.  examples:

 a constant (or perhaps better, const) primary would also be useful
 in several other cases, including:

 - as a replacement for default-argument object binding

this is used when you want to pass an *object* into an inner function, 
rather than a name:

 def foo(value, bar=fie.fum):
 if value == bar:
 ...

can be written

 def foo(value):
 if value == const bar:
 ...

 - local dispatch tables, and other generated-but-static data structures

 def foo(value):
 table = const {
 1: one,
 2: two,
 3: fie.fum,
 }

(maybe static would be a better keyword?)

 - explicit (but still anonymous) constant/expression folding

 def foo(value):
 if value  const (math.pi / 2):
 ...

and so on.  to implement this, the runtime simply evaluates the const 
expressions together with the default value expressions, and assigns the 
result to some func_xxx attribute.  everything else works as usual.

/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] Switch statement

2006-06-22 Thread Phillip J. Eby
I think one of the problems I sometimes have in communicating with you is 
that I think out stuff from top to bottom of an email, and sometimes 
discard working assumptions once they're no longer needed.  We then end up 
having arguments over ideas I already discarded, because you find the 
problems with them faster than I do, and you assume that those problems 
carry through to the end of my message.  :)  So, I'm partially reversing 
the order of my reply, so you can see what I'm actually proposing, before 
the minutiae of responding the objections you raised to stuff I threw out 
either in my previous message or the message before that.   Hopefully this 
will help.


At 10:44 AM 6/22/2006 -0700, Guido van Rossum wrote:
Please, think through the notion of const declarations more before
posting again. Without const declarations none of this can work

Actually, the const declaration part isn't necessary and I already 
discarded the idea in my  previous reply to you, noting that the 
combination of these facets can be made to work without any explicit const 
declarations:

1. case (literal|NAME) is the syntax for equality testing -- you can't 
use an arbitrary expression, not even a dotted name.

2. NAME, if used, must be bound at most once in its defining scope

3. Dictionary optimization can occur only for literals and names not bound 
in the local scope, others must use if-then.

This doesn't require explicit const declarations at all.  It does, 
however, prohibit using import A and then switching on a bunch of A.foo 
values.  You have to from A import foo, bar, baz instead.

If you like this, then you may not need to read the rest of this message, 
because most of your remaining comments and questions were based on an 
assumption that const declarations were necessary.


On 6/22/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
  At 09:37 AM 6/22/2006 -0700, Guido van Rossum wrote:
  On 6/22/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
This hypothetical const would be a *statement*,
executed like any other statement.  It binds a name to a value -- and
produces an error if the value changes.  The compiler doesn't need 
 to know
what it evaluates to at runtime; that's what LOAD_NAME or 
 LOAD_DEREF are
for.  ;)
  
  Please think this through more. How do you implement the produces an
  error if the value changes part? Is the const property you're
  thinking of part of the name or of the object it refers to?
  
  The only way I can see it work is if const-ness is a compile-time
  property of names, just like global. But that requires too much
  repetition when a constant is imported.
 
  Right; MAL pointed that out in the message I was replying to, and I
  conceded his point.  Of course, if you consider constness to be an implicit
  property of imported names that aren't rebound, the repetition problem goes
  away.

Um, technically names are never imported, only objects. Suppose module
A defines const X = 1, and module B imports A. How does the compiler
know that A.X is a constant?

It doesn't.  You have to from A import X.  At that point, you have a name 
that is bound by an import that can be considered constant as long as the 
name isn't rebound later.


  And if you then require all case expressions to be either literals or
  constant names, we can also duck the when does the expression get
  evaluated? question.  The obvious answer is that it's evaluated wherever
  you bound the name, and the compiler can either optimize the switch
  statement (or not), depending on where the assignment took place.

I don't understand what you're proposing. In particular I don't
understand what you mean by wherever you bound the name.

So (evading the import problem for a moment) suppose we have

const T = int(time.time())

def foo(x):
   switch x:
 case T: print Yes
 else: print No

Do you consider that an optimizable switch or not?

Yes.  What I'm trying to do is separate when the dictionary is 
constructed from when the expression is evaluated.  If we restrict the 
names used to names that have at most one binding in their defining scope, 
then we can simply add the dictionary entries whenever the *name is 
bound*.  Ergo, the evaluation time is apparent from simple reading of the 
source - we are never moving the evaluation, only determining how early we 
can add information to the switching dictionary.

Thus, the answer to when is the expression evaluated is when it's 
executed as seen in the source code.  There is thus no magic of either 
first-use or function-definition involved.  What you see is exactly what 
you get.


  A switch
  that's in a loop or a function call can only be optimized if all its
  constants are declared outside the loop or function body; otherwise it
  degrades to an if/elif chain.

What do you mean by a switch in a function call? Syntactically that
makes no sense. Do you mean in a function definition?

Yes, sorry.  I probably copied the slip from your previous post.  

Re: [Python-Dev] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Fredrik Lundh [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  So the constant would be evaluated at function definition time? I find
  that rather confusing.

 well, I find the proposed magic behaviour of case at least as confusing...

It's not magic if it can be explained. def goes over all the cases
and evaluates them in the surrounding scope and freezes the meaning of
the cases that way as long as the function object survives is not
magic.

  (except for the default argument thing; see above).  the result is a
  kind of semi-constant objects that would be useful, but perhaps not
  constant enough...)
 
  I fail to see the usefulness of this wrapper. The wrapper isn't
  completely transparent o some code that uses type checks may need to
  be modified. The wrapper doesn't get removed by a simple assignment;
  after
 
const a = 1
b = a
 
  how do we prevent b from being treated as a constant?

 we cannot -- this approaches assigns (a small amount of) const-ness to
 objects, not names.

OK, so neither a nor b is really a constant; it's just that they have
a value that is a constant wrapper.

I'm still confused how this wrapper would be used at run time.
(Because at compile time we *don't* generally know whether a
particular value contains a const wrapper or not.)

  it might be too much C# exposure, but I think I prefer the explicit
  when using approach...
 
  It may be not enough C# exposure, but I don't know exactly which
  approach you are referring to.

 the original one: if you want to treat an expression as a constant, you
 have to be explicit.  examples:

  a constant (or perhaps better, const) primary would also be useful
  in several other cases, including:
 
  - as a replacement for default-argument object binding

 this is used when you want to pass an *object* into an inner function,
 rather than a name:

  def foo(value, bar=fie.fum):
  if value == bar:
  ...

 can be written

  def foo(value):
  if value == const bar:
  ...

  - local dispatch tables, and other generated-but-static data structures

  def foo(value):
  table = const {
  1: one,
  2: two,
  3: fie.fum,
  }

 (maybe static would be a better keyword?)

At least it resembles the corresponding C keyword better than 'const'.

'static' tells me something useful (at least if I know C/C++/Java).
And I have some idea on how to implement it (not so different from the
def-time switch freezing).

However it should be

  static table = {...}

But I don't see how this would require the const-wrapper.

And I still think that this is not as nice as def-time freezing
switches; static or const causes clumsy syntax when importing
constants from another module since you have to repeat the const-ness
for each imported constant in each importing module.

  - explicit (but still anonymous) constant/expression folding

  def foo(value):
  if value  const (math.pi / 2):
  ...

 and so on.  to implement this, the runtime simply evaluates the const
 expressions together with the default value expressions, and assigns the
 result to some func_xxx attribute.  everything else works as usual.

Yup, got it. This is clearly implementable and has clear semantics.

-- 
--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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
 I think one of the problems I sometimes have in communicating with you is
 that I think out stuff from top to bottom of an email, and sometimes
 discard working assumptions once they're no longer needed.  We then end up
 having arguments over ideas I already discarded, because you find the
 problems with them faster than I do, and you assume that those problems
 carry through to the end of my message.  :)

You *do* have a text editor that lets you go back to the top of the
draft to remove discarded ideas, don't you? :-)

It's a reasonable form of discourse to propose an idea only to shoot
it down, but usually this is introduced by some phrase that hints to
the reader what's going to happen. You can't expect the reader to read
the entire email before turning on their brain. :)

 So, I'm partially reversing
 the order of my reply, so you can see what I'm actually proposing, before
 the minutiae of responding the objections you raised to stuff I threw out
 either in my previous message or the message before that.   Hopefully this
 will help.

 At 10:44 AM 6/22/2006 -0700, Guido van Rossum wrote:
 Please, think through the notion of const declarations more before
 posting again. Without const declarations none of this can work

 Actually, the const declaration part isn't necessary and I already
 discarded the idea in my  previous reply to you, noting that the
 combination of these facets can be made to work without any explicit const
 declarations:

 1. case (literal|NAME) is the syntax for equality testing -- you can't
 use an arbitrary expression, not even a dotted name.

But dotted names are important! E.g. case re.DOTALL. And sometimes
compile-time constant expressions are too. Example: case sys.maxint-1.

 2. NAME, if used, must be bound at most once in its defining scope

That's fine -- but doesn't extend to dotted names.

 3. Dictionary optimization can occur only for literals and names not bound
 in the local scope, others must use if-then.

So this wouldn't be optimized?!

NL = \n
for line in sys.stdin:
  switch line:
abc\n: ...
NL: ...

 This doesn't require explicit const declarations at all.  It does,
 however, prohibit using import A and then switching on a bunch of A.foo
 values.  You have to from A import foo, bar, baz instead.

 If you like this, then you may not need to read the rest of this message,
 because most of your remaining comments and questions were based on an
 assumption that const declarations were necessary.

I like it better than const declarations, but I don't like it as much
as the def-time-switch-freezing proposal; I find the limitiation to
simple literals and names too restrictive, and there isn't anything
else like that in Python. I also don't like the possibility that it
degenerates to if/elif. I like predictability. I like to be able to
switch on dotted names.

Also, when using a set in a case, one should be able to use an
expression like s1|s2 in a case.

-- 
--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] Switch statement

2006-06-22 Thread M.-A. Lemburg
Guido van Rossum wrote:
 Without const declarations none of this can work and
 the at-function-definition-time freezing is the best, because most
 predictable, approach IMO.

I you like this approach best, then how about using the same
approach as we have for function default argument values:

Variables which are to be regarded as constant within the
scope of the function are declared as such by using a const
declaration (much like we already have with the
global declaration).

a,b,c,d = range(4)
defvalue = 1

def switch(x=defvalue):
const a,b,c,d
switch x:
case a: return 'foo'
case b: return 'foo'
case c: return 'foo'
case d: return 'foo'
else: raise ValueError(x)

This declaration would cause the compiler to generate
LOAD_NAME opcodes just like for defvalue which then gets
executed at code object execution time, ie. when the
function is created.

This would also work out for the solution 1 case
in the PEP (if-elif-else)... hinthint :-)

def switch(x=defvalue):
const a,b,c,d
if x == a: return 'foo'
elif x == b: return 'bar'
elif x == c: return 'baz'
elif x == d: return 'bazbar'
else: raise ValueError(x)

Furthermore, the compiler could protect the constant
names from assignments (much in the same way it
applies special treatment to variables declared global
in a scope).

A nice side-effect would be that could easily use the
same approach to replace the often used default-argument-hack,
e.g.

def fraction(x, int=int, float=float):
return float(x) - int(x)

This would then read:

def fraction(x):
const int, float
return float(x) - int(x)

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Jun 22 2006)
 Python/Zope Consulting and Support ...http://www.egenix.com/
 mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
 mxODBC, mxDateTime, mxTextTools ...http://python.egenix.com/

2006-07-03: EuroPython 2006, CERN, Switzerland  10 days left

::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! 
___
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] Switch statement

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

 well, I find the proposed magic behaviour of case at least as confusing...
 
 It's not magic if it can be explained. def goes over all the cases
 and evaluates them in the surrounding scope and freezes the meaning of
 the cases that way as long as the function object survives is not
 magic.

well, people find def goes over all default values and evaluates them 
in the surrounding scope (etc) pretty confusing, and the default values 
are all part of the function header.  here you're doing the same thing 
for some expressions *inside* the function body, but not all.  it might 
be easy to explain, but I don't think it's easy to internalize.

 I'm still confused how this wrapper would be used at run time.
 (Because at compile time we *don't* generally know whether a
 particular value contains a const wrapper or not.)

oh, it would require the compiler to check for const-ness on globals 
when the function object is created, which would work for simple names, 
and require some yet-to-be-determined-handwaving-hackery for anything 
else...

 - local dispatch tables, and other generated-but-static data structures
  def foo(value):
  table = const {
  1: one,
  2: two,
  3: fie.fum,
  }

 (maybe static would be a better keyword?)
 
 At least it resembles the corresponding C keyword better than 'const'.
 
 'static' tells me something useful (at least if I know C/C++/Java).
 
 And I have some idea on how to implement it (not so different from the
 def-time switch freezing).
 
 However it should be
 
   static table = {...}

I'm not sure it should, actually -- the primary form is more flexible, 
and it better matches how things work: it's the expression that's 
special, not the variable.

and things like

 radian = degree * static (math.pi / 180)

would be pretty nice, for those of us who likes our Python fast.

 But I don't see how this would require the const-wrapper.

it wouldn't.

 And I still think that this is not as nice as def-time freezing
 switches; static or const causes clumsy syntax when importing
 constants from another module since you have to repeat the const-ness
 for each imported constant in each importing module.

well, the point is that you only have to spell it out if you actually 
care about things being constant/static/evaluated once/early, and when 
you do, it's always obvious for the reader what you're doing.

/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] Switch statement

2006-06-22 Thread Ka-Ping Yee
On Wed, 21 Jun 2006, Guido van Rossum wrote:
 I worry (a bit) about this case:

   y = 12
   def foo(x, y):
 switch x:
 case y: print something

 which to the untrained observer (I care about untrained readers much
 more than about untrained writers!) looks like it would print
 something if x equals y, the argument, while in fact it prints
 something if x equals 12.

I am quite concerned about this case too.  I think if Python were
to behave this way, it would be a new pitfall for people learning
the language -- like other pitfalls such as using unbound locals,
mutable default arguments, or the historical non-nested scopes.
I'm not saying the other pitfalls don't have good reasons -- some
are outweighed by other design advantages (unbound locals are a
consequence of having no variable declarations) and some have
since been fixed (like nested scopes).  But i'd be wary of adding
a new pitfall to that list without a very substantial win.

 Me too. I guess I was just pointing out that just evaluating it in
 the global scope would not give an error, just like this is valid (but
 confusing):

 y = 12
 def foo(y=y):
   print y
 y = 13
 foo()  # prints 12

I see how frozen-cases and default-arguments could have comparable
semantics, but i do think frozen-cases are more confusing.  In this
default-arguments example, there is at least a hint from the syntax
that we're introducing a new local variable, so there is a landmark
where the reader can hang the mental note that a new thing is being
introduced.  Also, it is easier to see that default arguments are
being fixed at function-definition time because their value
expressions are localized in the source code in the def line, a
line that makes sense to be evaluating at definition time.

For frozen-cases, you don't have this kind of landmark, and the bits
that are evaluated at function-definition time are scattered and
mixed with the rest of the function evaluated at function-call time.
That's pretty subtle; i can't think of any other Python construct
off the top of my head that mixes evaluation times like that.  (Yes,
the compiler does optimize literals, but it's done in a way that
doesn't affect semantics.)


-- ?!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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Fredrik Lundh [EMAIL PROTECTED] wrote:
 Guido van Rossum wrote:
  It's not magic if it can be explained. def goes over all the cases
  and evaluates them in the surrounding scope and freezes the meaning of
  the cases that way as long as the function object survives is not
  magic.

 well, people find def goes over all default values and evaluates them
 in the surrounding scope (etc) pretty confusing, and the default values
 are all part of the function header.

I think it's more surprising than confusing, in the same way as
mutable class variables are, or the sharing that follows from a = [];
b = a.

The switch proposal has less opportunity for this particular surprise
because the case expressions must be immutable (or at least hashable,
which pretty much boils down to the same thing).

 here you're doing the same thing
 for some expressions *inside* the function body, but not all.  it might
 be easy to explain, but I don't think it's easy to internalize.

It's hard to see how it will lead to actual surprises given even only
moderately decent coding style (which would imply not changing global
variables as implied parameters).

  I'm still confused how this wrapper would be used at run time.
  (Because at compile time we *don't* generally know whether a
  particular value contains a const wrapper or not.)

 oh, it would require the compiler to check for const-ness on globals
 when the function object is created, which would work for simple names,
 and require some yet-to-be-determined-handwaving-hackery for anything
 else...

I'd like to see more examples that show how it works. Some simple
this works, that doesn't, because... demos.

  - local dispatch tables, and other generated-but-static data structures
   def foo(value):
   table = const {
   1: one,
   2: two,
   3: fie.fum,
   }
 
  (maybe static would be a better keyword?)
 
  At least it resembles the corresponding C keyword better than 'const'.
 
  'static' tells me something useful (at least if I know C/C++/Java).
 
  And I have some idea on how to implement it (not so different from the
  def-time switch freezing).
 
  However it should be
 
static table = {...}

 I'm not sure it should, actually -- the primary form is more flexible,
 and it better matches how things work: it's the expression that's
 special, not the variable.

OK, I think I see how this works. You pre-compute the expression at
def-time, squirrel it away in a hidden field on the function object,
and assign it to a local each time the statement is executed. So this
would be allowed?

  a = static 1
  a = static 2  # same variable

 and things like

  radian = degree * static (math.pi / 180)

 would be pretty nice, for those of us who likes our Python fast.

No argument there.

  And I still think that this is not as nice as def-time freezing
  switches; static or const causes clumsy syntax when importing
  constants from another module since you have to repeat the const-ness
  for each imported constant in each importing module.

 well, the point is that you only have to spell it out if you actually
 care about things being constant/static/evaluated once/early, and when
 you do, it's always obvious for the reader what you're doing.

Unfortunately this would probably cause people to write

  switch x:
case static re.DOTALL: ...
case static re.IGNORECASE: ...

which is just more work to get the same effect as the
def-time-switch-freezing proposal.

I'm also unclear on what you propose this would do *without* the
statics. Would it be a compile-time error? Compile the dict each time
the switch is executed? Degenerate to an if/elif chain? Then what if x
is unhashable? What if *some* cases are static and others aren't?

Also, do you still see any use for the const wrapper that you brought
up earlier? I don't at this point.

-- 
--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] Switch statement

2006-06-22 Thread Georg Brandl
M.-A. Lemburg wrote:

 A nice side-effect would be that could easily use the
 same approach to replace the often used default-argument-hack,
 e.g.
 
 def fraction(x, int=int, float=float):
 return float(x) - int(x)
 
 This would then read:
 
 def fraction(x):
 const int, float
 return float(x) - int(x)

There's a certain risk that the premature-optimization fraction will
plaster every function with const declarations, but they write
unreadable code anyway ;)

Aside from this, there's still another point: assume you have quite a
number of module-level string constants which you want to use in a switch.
You'd have to repeat all of their names in a const declaration in order
to use them this way.

Georg

___
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] Switch statement

2006-06-22 Thread Ka-Ping Yee
On Wed, 21 Jun 2006, Guido van Rossum wrote:
 (Note how I've switched to the switch-for-efficiency camp, since it
 seems better to have clear semantics and a clear reason for the syntax
 to be different from if/elif chains.)

I don't think switch-for-efficiency (at least if efficiency is the
primary design motivator) makes sense without some strong evidence
that the use of if/elif constructs often causes a severe speed problem
in many Python programs.  (Premature optimization and all that.)
Long if/elif chains probably don't occur often enough or slow down
programs enough to invent syntax *just* for speed; and even if they
did, i don't think there's any precedent for a Python statement
invented primarily as a speed optimization.

I'm hoping we can talk more about the question: How can a new statement
help programmers express their intent more clearly?

So far i've seen two possible answers to that question:

1.  The switched-on expression is written and evaluated just once.

2.  The cases could help you unpack things into local variables.

(There was some discussion about unpacking earlier:
http://mail.python.org/pipermail/python-dev/2005-April/052780.html
which petered out, though there may still be the possibility of
designing something quite useful and readable.)

Any others?


-- ?!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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
 [Phillip]
 1. case (literal|NAME) is the syntax for equality testing -- you can't
 use an arbitrary expression, not even a dotted name.
 [Guido]
 But dotted names are important! E.g. case re.DOTALL. And sometimes
 compile-time constant expressions are too. Example: case sys.maxint-1.
 [Phillip]
 True - but at least you *can* use them, with from re import DOTALL and
 maxint_less_1 = sys.maxint-1.  You're just required to disambiguate
 *when* the calculation of these values is to be performed.

Yeah, but the result is a quite crippled case expression that's not
like anything in Python.

 2. NAME, if used, must be bound at most once in its defining scope
 
 That's fine -- but doesn't extend to dotted names.

 Right, hence #1.

Which I don't like.

(I know, I'm repeating myself here. Better than contradicting myself. :-)

 3. Dictionary optimization can occur only for literals and names not bound
 in the local scope, others must use if-then.
 
 So this wouldn't be optimized?!
 
 NL = \n
 for line in sys.stdin:
   switch line:
 abc\n: ...
 NL: ...

 This would result in a switch dictionary with abc\n in it, preceded by an
 if line==NL test.  So it's half-optimized.  The more literals, the more
 optimized.  If you put the same switch in a function body, it becomes fully
 optimized if the NL binding stays outside the function definition.

That still seems really weird, especially if you consider the whole
thing already being inside a def(). It would optimize references to
non-locals but not references to locals...?

 Note that you previously proposed a switch at top level not be optimized at
 all, so this is an improvement over that.

I don't particularly care about top-level switches; I don't expect
they'll be used much and I don't expect people to care about their
speed much. A for loop using some local variables is also quite slow
outside a function; if anybody complains we just tell them to put it
in a function.

I do care about switch/case being easy to use and flexible in likely
use cases, which include using constants defined in a different
module.

 I like it better than const declarations, but I don't like it as much
 as the def-time-switch-freezing proposal; I find the limitiation to
 simple literals and names too restrictive, and there isn't anything
 else like that in Python.

 Well, you can't def a dotted name, but I realize this isn't a binding.

You could have left that out of your email and we'd all have been happier. :-)

 I also don't like the possibility that it
 degenerates to if/elif. I like predictability.

 It is predictable: anything defined in the same scope will be if/elif,
 anything defined outside will be dict-switched.

But that's pretty subtle. I'd much rather see a rule that
*effectively* rules out non-constant cases completely. IMO the
def-time-switch-freeze proposal does this.

 I like to be able to switch on dotted names.
 Also, when using a set in a case, one should be able to use an
 expression like s1|s2 in a case.

 ...which then gets us back to the question of when the dots or | are
 evaluated.  My proposal forces you to make the evaluation time explicit,
 visible, and unquestionably obvious in the source, rather than relying on
 invisible knowledge about the function definition time.

At the cost of more convoluted code. It means in many cases I'd
probably continue to use if/elif chains because refactoring it into a
switch is too much effort. Thereby relegating switch to something only
used by speed freaks. While I want my switch to be fast, I don't want
it to be a freak.

 First time use is also a more visible approach, because it does not
 contradict the user's assumption that evaluation takes place where the
 expression appears.  The invisible assumption is only that subsequent
 execution will reuse the same expression results without recalculating them
 -- it doesn't *move* the evaluation somewhere else.

Have you made up your mind yet where the result of the first-time
evaluated value should be stored? On the function object? That implies
that it doesn't help for inner defs that are called only once per
definition (like certain callback patterns).

 I seem to recall that in general, Python prefers to evaluate expressions in
 the order that they appear in source code, and that we try to preserve that
 property as much as possible.  Both the names and literals only and
 first-time use approaches preserve that property; function definition
 time does not.

But first-time has the very big disadvantage IMO that there's no
safeguard to warn you that the value is different on a subsequent
execution -- you just get the old value without warning.

 Of course, it's up to you to weigh the cost and benefit; I just wanted to
 bring this one specific factor (transparency of the source) to your
 attention.  This whole const thread was just me trying to find another
 approach besides first-time use that preserves that 

Re: [Python-Dev] Switch statement

2006-06-22 Thread Phillip J. Eby
At 12:24 PM 6/22/2006 -0700, Guido van Rossum wrote:
OK, I think I see how this works. You pre-compute the expression at
def-time, squirrel it away in a hidden field on the function object,
and assign it to a local each time the statement is executed.

More precisely, I'd say that the computation is moved to function 
definition time and becomes an anonymous free variable.  The body of the 
static expression becomes a LOAD_DEREF of the free variable, rather than 
computation of the expression.

The debug trace will show the function definition going to the lines that 
contain the static expressions, but that's understandable.

I think I like it.  I was confused by what Fredrik meant by const, but 
your renaming it to static makes more sense to me; i.e. it belongs to the 
function, as opposed to each execution of the function.  (Whereas I was 
reading const as meaning immutable or non-rebindable, which made no 
sense in the context.)


Unfortunately this would probably cause people to write

   switch x:
 case static re.DOTALL: ...
 case static re.IGNORECASE: ...

which is just more work to get the same effect as the
def-time-switch-freezing proposal.

Without the static, the reordering of execution isn't obvious.  But 
perhaps that could be lived with, if the explanation was, well, static is 
implied by case.


I'm also unclear on what you propose this would do *without* the
statics. Would it be a compile-time error? Compile the dict each time
the switch is executed? Degenerate to an if/elif chain? Then what if x
is unhashable? What if *some* cases are static and others aren't?

If we allow non-static cases, then they should become ifs that happen 
prior to a dictionary lookup on the remaining static/literal ones.  Or we 
could just say that each adjacent block of static cases is its own 
dictionary lookup, and the rest happen in definition order.  (i.e., you 
replace contiguous static/literal runs with dictionary lookups, and 
everything else is if-elif.)

___
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] Switch statement

2006-06-22 Thread Phillip J. Eby
At 12:54 PM 6/22/2006 -0700, Guido van Rossum wrote:
Summarizing our disagreement, I think you feel that
freeze-on-first-use is most easily explained and understood while I
feel that freeze-at-def-time is more robust. I'm not sure how to get
past this point except by stating that you haven't convinced me... I
think it's time to sit back and wait for someone else to weigh in with
a new argument.

Which I think you and Fredrik have found, if case implies static.  It 
also looks attractive as an addition in its own right, independent of switch.

In any case, my point wasn't to convince you but to make you aware of 
certain costs and benefits that I wasn't sure you'd perceived.  It's clear 
from your response that you *have* perceived them now, so I'm quite 
satisfied by that outcome -- i.e., my goal wasn't to convince you to 
adopt a particular proposal, but rather to make sure you understood and 
considered the ramifications of the ones under discussion.

That being said, there isn't anything to get past; from my POV, the 
discussion is already a success.  :)

___
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] Switch statement

2006-06-22 Thread Guido van Rossum
On 6/22/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
 At 12:54 PM 6/22/2006 -0700, Guido van Rossum wrote:
 Summarizing our disagreement, I think you feel that
 freeze-on-first-use is most easily explained and understood while I
 feel that freeze-at-def-time is more robust. I'm not sure how to get
 past this point except by stating that you haven't convinced me... I
 think it's time to sit back and wait for someone else to weigh in with
 a new argument.

 Which I think you and Fredrik have found, if case implies static.  It
 also looks attractive as an addition in its own right, independent of 
 switch.

 In any case, my point wasn't to convince you but to make you aware of
 certain costs and benefits that I wasn't sure you'd perceived.  It's clear
 from your response that you *have* perceived them now, so I'm quite
 satisfied by that outcome -- i.e., my goal wasn't to convince you to
 adopt a particular proposal, but rather to make sure you understood and
 considered the ramifications of the ones under discussion.

 That being said, there isn't anything to get past; from my POV, the
 discussion is already a success.  :)

That sounds like a good solution all around. I hope that others can
also find themselves in this.

(1) An expression of the form 'static' atom has the semantics of
evaluating the atom at the same time as the nearest surrounding
function definition. If there is no surrounding function definition,
'static' is a no-op and the expression is evaluated every time.
[Alternative 1: this is an error] [Alternative 2: it is evaluated
before the module is entered; this would imply it can not involve any
imported names but it can involve builtins] [Alternative 3:
precomputed the first time the switch is entered]

(2) All case expressions in a switch have an implied 'static'.

(3) A switch is implemented using a dict which is precomputed at the
same time its static expressions are precomputed. The switch
expression must be hashable. Overlap between different cases will
raise an exception at precomputation time.

Independent from this, I wonder if we also need static names of the form

  static name = expression

which would be similar to

  name = static (expression)

but also prevents name from being assigned to elsewhere in the same scope.

Also, I haven't heard a lot of thumbs up or down on the idea of using

  case X:

to indicate a single value and

  case in S:

to indicate a sequence of values.

(I'm not counting all the hypergeneralizations that were proposed like

  case == X:
  case  X:
  case is X:
  case isinstance X:

since I'm -1 on all those, no matter how nicely they align.

:-)

-- 
--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] Switch statement

2006-06-21 Thread Ka-Ping Yee
On Wed, 21 Jun 2006, Phillip J. Eby wrote:
 Well, EIBTI and all that:

  switch x:
  case == 1: foo(x)
  case in S: bar(x)

 It even lines up nicely.  :)

Hmm, this is rather nice.  I can imagine possible use cases for

switch x:
case  3: foo(x)
case is y: spam(x)
case == z: eggs(x)

An interesting use case for which this offers no corresponding
syntax is

case instanceof ClassA: ham(x)

which doesn't work because Python spells a type test as
isinstance(a, b) rather than with an operator.  (I suppose
whether we want it to be an operator might be another
question to think about for Python 3000.)


-- ?!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] Switch statement

2006-06-21 Thread Georg Brandl
Ka-Ping Yee wrote:
 On Wed, 21 Jun 2006, Phillip J. Eby wrote:
 Well, EIBTI and all that:

  switch x:
  case == 1: foo(x)
  case in S: bar(x)

 It even lines up nicely.  :)
 
 Hmm, this is rather nice.  I can imagine possible use cases for
 
 switch x:
 case  3: foo(x)
 case is y: spam(x)

Ha, a slight reminiscence of BASIC...

 case == z: eggs(x)
 
 An interesting use case for which this offers no corresponding
 syntax is
 
 case instanceof ClassA: ham(x)
 
 which doesn't work because Python spells a type test as
 isinstance(a, b) rather than with an operator.  (I suppose
 whether we want it to be an operator might be another
 question to think about for Python 3000.)

FWIW, I like is a most, but there's no way to spell this
as one word without confusing readers.

Georg

___
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] Switch statement

2006-06-21 Thread Nick Coghlan
Greg Ewing wrote:
 Phillip J. Eby wrote:
 
 Actually, one could consider case expressions to be computed at function 
 definition time, the way function defaults are.  That would solve the 
 problem of symbolic constants, or indeed any sort of expressions.
 
 That's an excellent idea!
 
 It's just a question of which one is easier to explain. 
 
 I think the function-definition-time one is easiest to
 both explain and also to reason about when writing code,
 since definition time is well-defined, whereas the first
 time it's executed is somewhat fuzzy.

There's some benefit to first time it's executed though:
   a. it allows access to the local namespace
   b. it uses the same semantics at module level as it does in a function

If we go with 'at function definition time', then neither of those is true. 
I'm actually curious how a module level switch statement would work at all in 
that case, without either falling back on the first time it's executed 
definition, or else not permitting switch statements in module level code.

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] Switch statement

2006-06-21 Thread Phillip J. Eby
At 03:38 AM 6/21/2006 -0500, Ka-Ping Yee wrote:
On Wed, 21 Jun 2006, Phillip J. Eby wrote:
  Well, EIBTI and all that:
 
   switch x:
   case == 1: foo(x)
   case in S: bar(x)
 
  It even lines up nicely.  :)

Hmm, this is rather nice.  I can imagine possible use cases for

 switch x:
 case  3: foo(x)
 case is y: spam(x)
 case == z: eggs(x)

An interesting use case for which this offers no corresponding
syntax is

 case instanceof ClassA: ham(x)

Actually, I was assuming that any other operator besides == and 'in' would 
be relegated to an if-elif chain in the default case, although it's almost 
possible to do that automatically, I suppose.

___
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] Switch statement

2006-06-21 Thread Guido van Rossum
On 6/21/06, Nick Coghlan [EMAIL PROTECTED] wrote:
 There's some benefit to first time it's executed though:
a. it allows access to the local namespace

And how would that be a good thing? It just begs for confusion if the
local variable doesn't always have the same value. (Yes, globals may
vary too, but less likely, since global *variables* (i.e. that
actually vary) are generally considered a bad idea. There's no such
taboo for local variables. :-)

b. it uses the same semantics at module level as it does in a function

Hm, I hadn't thought of that one yet.

 If we go with 'at function definition time', then neither of those is true.
 I'm actually curious how a module level switch statement would work at all in
 that case, without either falling back on the first time it's executed
 definition, or else not permitting switch statements in module level code.

After thinking about it a bit I think that if it's not immediately
contained in a function, it should be implemented as alternative
syntax for an if/elif chain.

-- 
--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] Switch statement

2006-06-21 Thread Guido van Rossum
On 6/21/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
 At 03:38 AM 6/21/2006 -0500, Ka-Ping Yee wrote:
 On Wed, 21 Jun 2006, Phillip J. Eby wrote:
   Well, EIBTI and all that:
  
switch x:
case == 1: foo(x)
case in S: bar(x)
  
   It even lines up nicely.  :)
 
 Hmm, this is rather nice.  I can imagine possible use cases for
 
  switch x:
  case  3: foo(x)
  case is y: spam(x)
  case == z: eggs(x)
 
 An interesting use case for which this offers no corresponding
 syntax is
 
  case instanceof ClassA: ham(x)

 Actually, I was assuming that any other operator besides == and 'in' would
 be relegated to an if-elif chain in the default case, although it's almost
 possible to do that automatically, I suppose.

I've been thinking about generalization to other operators too, but
decided that it would be a mistake. It would be quite clumsy to
explain the exact semantics: if all operators are == or in an
efficient hash table gets pre-constructed at function definition time,
otherwise, um..., what exactly?

(Note how I've switched to the switch-for-efficiency camp, since it
seems better to have clear semantics and a clear reason for the syntax
to be different from if/elif chains.)

-- 
--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] Switch statement

2006-06-21 Thread Phillip J. Eby
At 09:16 AM 6/21/2006 -0700, Guido van Rossum wrote:
After thinking about it a bit I think that if it's not immediately
contained in a function, it should be implemented as alternative
syntax for an if/elif chain.

That worries me a little.  Suppose I write a one-off script like this:

for line in sys.stdin:
 words = line.split()
 if words:
 switch words[0]:
 case foo: blah
 case words[-1]: print mirror image!

Then, if I later move the switch into a function, it's not going to mean 
the same thing any more.  If the values are frozen at first use or 
definition time (which are the same thing for module-level code), then I'll 
find the lurking bug sooner.

OTOH, breaking it sooner doesn't seem like such a great idea either; seems 
like a recipe for a newbie-FAQ, actually.  ISTM that the only sane way to 
deal with this would be to ban the switch statement at module level, which 
then seems to be an argument for not including the switch statement at all.  :(

I suppose the other possibility would be to require at compilation time 
that a case expression include only non-local variables.  That would mean 
that you couldn't use *any* variables in a case expression at module-level 
switch, but wording the error message for that to not be misleading might 
be tricky.

I suppose an error message for the above could simply point to the fact 
that 'words' is being rebound in the current scope, and thus can't be 
considered a constant.  This is only an error at the top-level if the 
switch appears in a loop, and the variable is rebound somewhere within that 
loop or is rebound more than once in the module as a whole (including 
'global' assignments in functions).

___
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] Switch statement

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

 (Note how I've switched to the switch-for-efficiency camp, since it
 seems better to have clear semantics and a clear reason for the syntax
 to be different from if/elif chains.)

if you're now in the efficiency camp, why not just solve this on the 
code generator level ?  given

 var = some expression
 if var == constant:
 ...
 elif var == constant:
 ...

let the compiler use a dispatch table, if it can and wants to.

/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] Switch statement

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

  (Note how I've switched to the switch-for-efficiency camp, since it
  seems better to have clear semantics and a clear reason for the syntax
  to be different from if/elif chains.)

 if you're now in the efficiency camp, why not just solve this on the
 code generator level ?  given

  var = some expression
  if var == constant:
  ...
  elif var == constant:
  ...

 let the compiler use a dispatch table, if it can and wants to.

But in most cases the 'constant' is actually an expression involving a
global, often even a global in another module. (E.g. sre_compile.py)
The compiler will have a hard time proving that this is really a
constant, so it won't optimize the code.

The proposed switch semantics (create the table when the containing
function is defined) get around this by defining what it means by
constant.

BTW I would like references to locals shadowing globals to be flagged
as errors (or at least warnings) so that users who deduced the wrong
mental model for a switch statement are caught out sooner.

-- 
--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] Switch statement

2006-06-21 Thread Guido van Rossum
On 6/21/06, Phillip J. Eby [EMAIL PROTECTED] wrote:
 At 09:16 AM 6/21/2006 -0700, Guido van Rossum wrote:
 After thinking about it a bit I think that if it's not immediately
 contained in a function, it should be implemented as alternative
 syntax for an if/elif chain.

 That worries me a little.  Suppose I write a one-off script like this:

 for line in sys.stdin:
  words = line.split()
  if words:
  switch words[0]:
  case foo: blah
  case words[-1]: print mirror image!

Why would you write a script like that? If you've learned the
idiomatic use of a switch statement first, that would never occur to
you. If you're totally clueless, I don't really care that much.

 Then, if I later move the switch into a function, it's not going to mean
 the same thing any more.

And it will be a clear compile-time warning because in the refactored
version you'd be attempting to use a local variable in a case.

 If the values are frozen at first use or
 definition time (which are the same thing for module-level code), then I'll
 find the lurking bug sooner.

Or not, depending on how easily the misbehavior is spotted from a
cursory glance at the output.

 OTOH, breaking it sooner doesn't seem like such a great idea either; seems
 like a recipe for a newbie-FAQ, actually.  ISTM that the only sane way to
 deal with this would be to ban the switch statement at module level, which
 then seems to be an argument for not including the switch statement at all.  
 :(

I don't understand this line of reasoning. The semantics I propose are
totally well-defined.

 I suppose the other possibility would be to require at compilation time
 that a case expression include only non-local variables.  That would mean
 that you couldn't use *any* variables in a case expression at module-level
 switch, but wording the error message for that to not be misleading might
 be tricky.

That seems overly restrictive given that I expect *most* cases to use
named constants, not literals.

 I suppose an error message for the above could simply point to the fact
 that 'words' is being rebound in the current scope, and thus can't be
 considered a constant.  This is only an error at the top-level if the
 switch appears in a loop, and the variable is rebound somewhere within that
 loop or is rebound more than once in the module as a whole (including
 'global' assignments in functions).

Let's not focus on the error message. I think your assumption that
every switch at the global level ought to be able to be moved into a
function and work the same way is not a particularly important
requirement.

(As a compromise, a switch at the global level with only literal cases
could be efficiently optimized. This should include compile-time
constant expressions.)

BTW a switch in a class should be treated the same as a global switch.
But what about a switch in a class in a function?

-- 
--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


  1   2   >