2009/12/15 Shlomi Fish <shlo...@iglu.org.il>: > On Tuesday 15 Dec 2009 15:53:28 Philip Potter wrote: >> How can "Illegal division by zero" be a compile-time error? It seems >> clear to me that it's a run-time error, which the optimizer has >> (wrongly) decided to raise at compile-time. >> > > Well, the Perl compiler tends to collapse constants. So if it sees something > like: > > <<< > ... ( CONSTANT_EXPR() / 0 ) ... >>>> > > it will try to find the value of "CONSTANT_EXPR() / 0" so it can optimise it > as a constant for the interpreter, and then get a fault there. It's a standard > optimisation technique that also exists in other compilers such as gcc that > are collapsing such constant expressions. So it does get evaluated at compile- > time and as such should be avoided.
I'm well aware of constant folding, and yes it is a standard technique. But your description of it is incorrect. If evaluating a constant expression results in a runtime exception, that runtime exception must happen at runtime, and not at compile time. In general, it is the duty of an optimizer never to change program behaviour, only performance. Therefore an optimizer which tries to fold a constant expression at compile time only to find a divide by zero exception should write code which raises a divide by zero exception at runtime. Raising a divide by zero exception at compile time is not what the original program did, and so it's not what the optimizer should do either. If an optimizer *were* allowed to move runtime errors to compile time, it wouldn't just prevent use of 1/0. The following reasonable (if unrealistic) example would not be guaranteed to compile: # Check if a division will emit any sort of exception (divide by zero, overflow, underflow, NaN, whatever) sub check_division { my ($n, $d) = @_; eval { $n/$d}; return "Invalid division" if $@; return "Valid division"; } # and elsewhere... check_division(1,0); Why? Because if a sufficiently clever optimizer saw that somewhere in your code you call check_division(1,0), it could decide to inline the function there. And once it's done that, it can propagate the constants 1 and 0 into the local versions of the variables $n and $d, producing the constant expression 1/0 within the eval block. Now it merrily decides to calculate this expression's value at compile time, only to emit a compile-time error. If this error had happened at runtime, the program would have caught it and functioned entirely correctly; but by moving the exception to compile time -- and out of the eval block which was supposed to catch any exceptions -- the program won't even compile. If I am supposed to defend against such an overzealous optimizer, how would I write code that uses any block eval to catch exceptions? A sufficiently advanced optimizer could always use some method like that described above to precalculate the results of the eval, triggering an exception at compile time instead of runtime. Therefore block eval could never be guaranteed to catch runtime exceptions! Philip -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/