Multiple expression eval in compound if statement?
I'm horsing around with recognizing switch-like if statements like: if x == 1: print 1 elif x == 2: print 2 else: print "unknown" in the compiler and generating O(1) code. "x" can be any expression, but must be precisely the same in each elif clause, the comparison operator must be "==" and the RHS of the test must evaluate to a simple hashable constant (string, float, integer - still working on None, constant tuples may be allowed later). I can currently recognize such constructs and am working on code generation. This would represent a semantic change to the Python runtime, because x would only be evaluated once, whereas in existing usage it can potentially be evaluated many times. If evaluating x has side-effects, code like the above that currently works would break. In reading the language reference manual, it says: It selects exactly one of the suites by evaluating the expressions one by one until one is found to be true (see section 5.10 for the definition of true and false); then that suite is executed (and no other part of the if statement is executed or evaluated). If all expressions are false, the suite of the else clause, if present, is executed. It says nothing about possibly caching values, which is what I'm doing effectively, but it seems pretty clear that each full test expression will be evaluated until one evaluates to true. I can't imagine anyone relying on a side-effect when evaluating x in this context, and if someone did, their code would be truly fragile. Still, any thought as to whether or not such a semantic change to the language might be acceptable? Skip
I'm horsing around with recognizing switch-like if statements like:
if x == 1: print 1 elif x == 2: print 2 else: print "unknown"
in the compiler and generating O(1) code. "x" can be any expression, but must be precisely the same in each elif clause, the comparison operator must be "==" and the RHS of the test must evaluate to a simple hashable constant (string, float, integer - still working on None, constant tuples may be allowed later). I can currently recognize such constructs and am working on code generation.
I think it unwise to allow x to be any expression. Besides altering existing semantics, it leads to code redundancy and to a fragile construct (where the slightest alteration of any of the expressions triggers a silent reversion to O(n) behavior). Raymond
On Jun 12, 2005, at 10:20 PM, Raymond Hettinger wrote:
I think it unwise to allow x to be any expression. Besides altering existing semantics, it leads to code redundancy and to a fragile construct (where the slightest alteration of any of the expressions triggers a silent reversion to O(n) behavior).
Yes, changing the semantics of the if statement would be pretty bad. Unless evaluating x provably has no side effects (e.g. accessing a local variable), I would say that the duplicate evaluations must not be eliminated.
if x == 1: print 1 elif x == 2: print 2 else: print "unknown"
Unfortunately, I'm afraid this will not be as useful as it at first appears, because python has no concept of a constant variable binding. I hardly ever see an if/else chain being done with hardcoded integers. Rather, more often a variable is compared to global "constants", which could not be optimized away. However, this construction does appear reasonably often with constant strings on the RHS, so there may actually be a real-world gain to be had. With a Sufficiently Smart Compiler, of course, you could make assumptions at runtime about values not changing, and recompile code depending upon that assumption if necessary, but that's more in the realm of a new runtime than modifications to CPython. Maybe PyPy will eventually provide the ability to do that kind of interesting optimization. James
Raymond> I think it unwise to allow x to be any expression. How do you decide what's "too complex"? Even an apparently simple variable can have side effects, so the semantic change bit is important no matter how complex the expression. (Consider the builtin help object. Type it at the prompt with no parens.) Like I said, "I'm horsing around with...". If this never makes it into Python I can accept that. The interesting thing for me at this point is the code generation anyway. I figure if Guido reconsiders PEP 275 (I think it covers all the bases), then the code generation stuff will probably be of some use. Skip
On Monday 13 June 2005 21:14, Skip Montanaro wrote:
Raymond> I think it unwise to allow x to be any expression.
How do you decide what's "too complex"? Even an apparently simple variable can have side effects, so the semantic change bit is important no matter how complex the expression. (Consider the builtin help object. Type it at the prompt with no parens.)
Note also that saying 'just a simple local variable' doesn't cut it, either,
because you will break on something like:
class stupid:
v = 0
def __eq__(self, other):
self.v += 1
return self.v == other
Really, you'd have to make sure you didn't optimise any LHS that defined
a comparision operator (I _think_ that covers all the cases).
Anthony
--
Anthony Baxter
Hi, Raymond Hettinger wrote:
I think it unwise to allow x to be any expression. Besides altering existing semantics, it leads to code redundancy and to a fragile construct (where the slightest alteration of any of the expressions triggers a silent reversion to O(n) behavior).
What would happen if 'x' were to be an object whose class has a __eq__ that is defined in an odd way, e.g. having side effects? Might this mean behaviour change even if 'x' is a local variable? yours, Gerrit Holl. -- Weather in Twenthe, Netherlands 18/06 17:25: 24.0°C wind 3.1 m/s NE (57 m above NAP) -- In the councils of government, we must guard against the acquisition of unwarranted influence, whether sought or unsought, by the military-industrial complex. The potential for the disastrous rise of misplaced power exists and will persist. -Dwight David Eisenhower, January 17, 1961
[Raymond Hettinger]
I think it unwise to allow x to be any expression. Besides altering existing semantics, it leads to code redundancy and to a fragile construct (where the slightest alteration of any of the expressions triggers a silent reversion to O(n) behavior).
[Gerrit Holl]
What would happen if 'x' were to be an object whose class has a __eq__ that is defined in an odd way, e.g. having side effects?
Every molecule in your body would simultaneously implode at the speed of light. Raymond
On 6/12/05, Skip Montanaro
I'm horsing around with recognizing switch-like if statements like:
if x == 1: print 1 elif x == 2: print 2 else: print "unknown"
in the compiler and generating O(1) code. "x" can be any expression, but must be precisely the same in each elif clause, the comparison operator must be "==" and the RHS of the test must evaluate to a simple hashable constant (string, float, integer - still working on None, constant tuples may be allowed later). I can currently recognize such constructs and am working on code generation.
Cool!
This would represent a semantic change to the Python runtime, because x would only be evaluated once, whereas in existing usage it can potentially be evaluated many times. If evaluating x has side-effects, code like the above that currently works would break.
In reading the language reference manual, it says:
It selects exactly one of the suites by evaluating the expressions one by one until one is found to be true (see section 5.10 for the definition of true and false); then that suite is executed (and no other part of the if statement is executed or evaluated). If all expressions are false, the suite of the else clause, if present, is executed.
It says nothing about possibly caching values, which is what I'm doing effectively, but it seems pretty clear that each full test expression will be evaluated until one evaluates to true.
I can't imagine anyone relying on a side-effect when evaluating x in this context, and if someone did, their code would be truly fragile. Still, any thought as to whether or not such a semantic change to the language might be acceptable?
I think it would be wiser if you only did this when x is a simple local variable. For locals, we *know* that no side effect of any expression can change the value. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
participants (6)
-
Anthony Baxter
-
Gerrit Holl
-
Guido van Rossum
-
James Y Knight
-
Raymond Hettinger
-
Skip Montanaro