Re: [Python-Dev] switch statement
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
> 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
[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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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