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