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/


Reply via email to