[Python-Dev] Switch statement (original) (raw)
Phillip J. Eby pje at telecommunity.com
Thu Jun 22 15:36:23 CEST 2006
- Previous message: [Python-Dev] Switch statement
- Next message: [Python-Dev] Switch statement
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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.
- Previous message: [Python-Dev] Switch statement
- Next message: [Python-Dev] Switch statement
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]