Re: capture error - the better way?
2009/12/18 Peter Scott pe...@psdt.com: On Wed, 16 Dec 2009 10:09:38 +, Philip Potter wrote: Yes, it can't fold the constant. That's no excuse for changing the behaviour of the program. What it should do is what I wrote in my previous email -- replace it with code that raises a runtime exception when executed -- ie a die Illegal division by zero. This is Perl. The distinction between the compilation and run time phases is almost totally academic. (For instance, use strict throws some exceptions at compile time and others at run time.) Since there's no compiled executable produced, the only difference in behavior is that your program dies sooner than it would have. Of course, conceivably it would not have died at all if the constant folding occurred in conditionally unexecuted code. So think of this as compile-time validation made possible by the use of constants: if your program *were* to execute that code, it would die. Better to know about that in advance than 49 hours into a 50 hour duty cycle. I don't disagree with most of what you said. Yes, runtime and compile time are not as clear as in a language like C. Yes, it's best to know as soon as possible that a program has a potential problem. But my issue is that here, no such problem exists, and yet perl is still complaining about it. Recall that the example here was a runtime error causing an exception to be thrown _from within an eval {} block_. If the program were to execute that code, it would not die, as you claim. It would instead throw an exception which would be caught by the eval {} block, recover, and continue. But by moving the runtime error to compile time, and outside of the systems that you've set up to deal with the error, perl is saying I think this code is broken when in fact it isn't. perl has changed the behaviour of the problem. I wouldn't mind if perl just issued a warning. Having a constant expression 1/0 in code is probably a Bad Thing which the programmer should be warned of. But since it's still valid code with a predictable outcome, it should do what it's told, not try to second guess what you wanted in some sort of DWIMery. Thankfully, the people who wrote perl 5.10 seem to agree with me. Phil -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
On Wed, 16 Dec 2009 10:09:38 +, Philip Potter wrote: 2009/12/16 Shlomi Fish shlo...@iglu.org.il: On Tuesday 15 Dec 2009 17:14:25 Philip Potter wrote: 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. But this is a case where the compiler evaluates a constant expression and it results in an exception. So it cannot store it as a folded constant on the side for the run-time place. As a result, it throws a compile-time error. Yes, it can't fold the constant. That's no excuse for changing the behaviour of the program. What it should do is what I wrote in my previous email -- replace it with code that raises a runtime exception when executed -- ie a die Illegal division by zero. This is Perl. The distinction between the compilation and run time phases is almost totally academic. (For instance, use strict throws some exceptions at compile time and others at run time.) Since there's no compiled executable produced, the only difference in behavior is that your program dies sooner than it would have. Of course, conceivably it would not have died at all if the constant folding occurred in conditionally unexecuted code. So think of this as compile-time validation made possible by the use of constants: if your program *were* to execute that code, it would die. Better to know about that in advance than 49 hours into a 50 hour duty cycle. Perl has never made a promise about compilation phase vs runtime phase separation of duties you appear to want. -- Peter Scott http://www.perlmedic.com/ http://www.perldebugged.com/ http://www.informit.com/store/product.aspx?isbn=0137001274 -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
On Tuesday 15 Dec 2009 17:14:25 Philip Potter wrote: 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. Why? 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. But this is a case where the compiler evaluates a constant expression and it results in an exception. So it cannot store it as a folded constant on the side for the run-time place. As a result, it throws a compile-time error. 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. Why? 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. Well, Perl's optimizer is not that smart. It does not inline such functions because it doesn't know how many places they will get called. So you're spared in this case. 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! Well, a program can always have user-input (from files, STDIN, @ARGV, etc.) which no compiler or optimiser can predict. Sometimes this input will trigger certain exceptions which cannot be folded. Regards, Shlomi Fish -- - Shlomi Fish http://www.shlomifish.org/ Original Riddles - http://www.shlomifish.org/puzzles/ Bzr is slower than Subversion in combination with Sourceforge. ( By: http://dazjorz.com/ ) -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
2009/12/16 Shlomi Fish shlo...@iglu.org.il: On Tuesday 15 Dec 2009 17:14:25 Philip Potter wrote: 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. But this is a case where the compiler evaluates a constant expression and it results in an exception. So it cannot store it as a folded constant on the side for the run-time place. As a result, it throws a compile-time error. Yes, it can't fold the constant. That's no excuse for changing the behaviour of the program. What it should do is what I wrote in my previous email -- replace it with code that raises a runtime exception when executed -- ie a die Illegal division by zero. 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. Why? Uhm, because it changes the behaviour of the program? I don't see what else I can say. If the optimizer changes program behaviour then you have no guarantee that what you wrote is what will happen. 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. Well, Perl's optimizer is not that smart. It does not inline such functions because it doesn't know how many places they will get called. So you're spared in this case. I don't think you understand my point. The point is: even if it could, it shouldn't. Once you allow optimizers to change program behaviour, you have no guarantee that what you write is what will happen. That is why optimizers must *never* change program behaviour. 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! Well, a program can always have user-input (from files, STDIN, @ARGV, etc.) which no compiler or optimiser can predict. Sometimes this input will trigger certain exceptions which cannot be folded. Sometimes the optimizer will be unable to break my code? That is no reassurance. Phil -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
From: Philip Potter philip.g.pot...@gmail.com 2009/12/16 Shlomi Fish shlo...@iglu.org.il: On Tuesday 15 Dec 2009 17:14:25 Philip Potter wrote: 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. But this is a case where the compiler evaluates a constant expression and it results in an exception. So it cannot store it as a folded constant on the side for the run-time place. As a result, it throws a compile-time error. Yes, it can't fold the constant. That's no excuse for changing the behaviour of the program. What it should do is what I wrote in my previous email -- replace it with code that raises a runtime exception when executed -- ie a die Illegal division by zero. An exception that get's raised every time is not very ... exceptional. What it should do is what it did. Tell you you are doing something stupid. Jenda = je...@krynicky.cz === http://Jenda.Krynicky.cz = When it comes to wine, women and song, wizards are allowed to get drunk and croon as much as they like. -- Terry Pratchett in Sourcery -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
On Tuesday 15 Dec 2009 09:50:27 Xiao Lan (小兰) wrote: Hello, It seems in ruby and python we have a good exception capturing way. The ruby's: irb(main):042:0 begin irb(main):043:1* x=12/0 irb(main):044:1 rescue irb(main):045:1 puts 0 div error irb(main):046:1 end 0 div error The python's: try: ... x=12/0 ... except: ... print 0 div error ... 0 div error But in Perl I have to use an eval: # perl -e ' eval $x=12/0; if ($@) { print 0 div error }' 0 div error So what's the equivalent of perl's exception handling like python/ruby? You can use block eval {} instead of string eval : #!/usr/bin/perl use strict; use warnings; my $x; eval { $x=12/0; }; if ($@) { print 0 div error\n; } One problem with that is that Perl 5's exception handling is not inherently object-oriented. If you'd like that (and you likely would), look at the following CPAN modules: * http://search.cpan.org/dist/Exception-Class/ * http://search.cpan.org/dist/TryCatch/ (never used it though). * http://search.cpan.org/dist/Try-Tiny/ (likewise). There's also http://search.cpan.org/dist/Error/ , which I've used, and have been co-maintaining, but cannot really recommend because it is Black Magick and quirky. Regards, Shlomi Fish Thanks in advance. -- - Shlomi Fish http://www.shlomifish.org/ Stop Using MSIE - http://www.shlomifish.org/no-ie/ Bzr is slower than Subversion in combination with Sourceforge. ( By: http://dazjorz.com/ ) -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
On Tue, Dec 15, 2009 at 6:34 PM, Shlomi Fish shlo...@iglu.org.il wrote: You can use block eval {} instead of string eval : #!/usr/bin/perl use strict; use warnings; my $x; eval { $x=12/0; }; if ($@) { print 0 div error\n; } I did have tried that, but this will get a runtime error. # perl -e ' eval { $x = 12/0 }; if ($@) { print 0 div error }' Illegal division by zero at -e line 2. My perl version: # perl -v This is perl, v5.8.8 built for i486-linux-thread-multi One problem with that is that Perl 5's exception handling is not inherently object-oriented. If you'd like that (and you likely would), look at the following CPAN modules: * http://search.cpan.org/dist/Exception-Class/ * http://search.cpan.org/dist/TryCatch/ (never used it though). * http://search.cpan.org/dist/Try-Tiny/ (likewise). Thanks Shlomi, I will check out them. -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
2009/12/15 Xiao Lan (小兰) practicalp...@gmail.com: On Tue, Dec 15, 2009 at 6:34 PM, Shlomi Fish shlo...@iglu.org.il wrote: You can use block eval {} instead of string eval : I did have tried that, but this will get a runtime error. # perl -e ' eval { $x = 12/0 }; if ($@) { print 0 div error }' Illegal division by zero at -e line 2. [OT: Are you running this as root? You should avoid being root whenever you can.] That's odd. It works on my machine: $ perl -le ' eval { $x = 12/0 }; if ($@) { print 0 div error }' 0 div error $ perl -v This is perl, v5.10.0 built for x86_64-linux-gnu-thread-multi I can only guess that perl5.8.8 is not catching exceptions in constants caused by evaluating compile time constants. String eval delays evaluation to runtime which would stop this bug manifesting; but this feature is exactly the reason why string eval is /bad/. Does this work for you? $ perl -le 'eval { die died; }; if ($@) { print Caught exception; }' I would expect this to print Caught exception and not died, which indeed is what happens on my machine. Phil -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
On Tue, Dec 15, 2009 at 7:50 PM, Xiao Lan (小兰) practicalp...@gmail.com wrote: I did have tried that, but this will get a runtime error. Sorry this is exactly a compile-time error. # cat except.pl eval { $x=12/0 }; print 0 div error if $@; # perl -c except.pl Illegal division by zero at except.pl line 2. So, can't we capture it at runtime when meeting such error? -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
On Tuesday 15 Dec 2009 14:25:28 Xiao Lan (小兰) wrote: On Tue, Dec 15, 2009 at 7:50 PM, Xiao Lan (小兰) practicalp...@gmail.com wrote: I did have tried that, but this will get a runtime error. Sorry this is exactly a compile-time error. # cat except.pl eval { $x=12/0 }; print 0 div error if $@; # perl -c except.pl Illegal division by zero at except.pl line 2. So, can't we capture it at runtime when meeting such error? No, you cannot capture compile-time errors at runtime. You'll need to make sure your code compiles before you run it. Note that you can capture such errors if you do perldoc -f require, perldoc -f do (for a filename), string eval , etc. at run-time, in which case perl 5 invokes its compiler to compile some code at run-time. But for run-time exceptions block eval { ... } should work just as well. Regards, Shlomi Fish -- - Shlomi Fish http://www.shlomifish.org/ Star Trek: We, the Living Dead - http://shlom.in/st-wtld Bzr is slower than Subversion in combination with Sourceforge. ( By: http://dazjorz.com/ ) -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
2009/12/15 Shlomi Fish shlo...@iglu.org.il: On Tuesday 15 Dec 2009 14:25:28 Xiao Lan (小兰) wrote: On Tue, Dec 15, 2009 at 7:50 PM, Xiao Lan (小兰) practicalp...@gmail.com wrote: I did have tried that, but this will get a runtime error. Sorry this is exactly a compile-time error. # cat except.pl eval { $x=12/0 }; print 0 div error if $@; # perl -c except.pl Illegal division by zero at except.pl line 2. So, can't we capture it at runtime when meeting such error? No, you cannot capture compile-time errors at runtime. You'll need to make sure your code compiles before you run it. Note that you can capture such errors if you do perldoc -f require, perldoc -f do (for a filename), string eval , etc. at run-time, in which case perl 5 invokes its compiler to compile some code at run-time. 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. Phil -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
On Tuesday 15 Dec 2009 15:53:28 Philip Potter wrote: 2009/12/15 Shlomi Fish shlo...@iglu.org.il: On Tuesday 15 Dec 2009 14:25:28 Xiao Lan (小兰) wrote: On Tue, Dec 15, 2009 at 7:50 PM, Xiao Lan (小兰) practicalp...@gmail.com wrote: I did have tried that, but this will get a runtime error. Sorry this is exactly a compile-time error. # cat except.pl eval { $x=12/0 }; print 0 div error if $@; # perl -c except.pl Illegal division by zero at except.pl line 2. So, can't we capture it at runtime when meeting such error? No, you cannot capture compile-time errors at runtime. You'll need to make sure your code compiles before you run it. Note that you can capture such errors if you do perldoc -f require, perldoc -f do (for a filename), string eval , etc. at run-time, in which case perl 5 invokes its compiler to compile some code at run-time. 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. Regards, Shlomi Fish Phil -- - Shlomi Fish http://www.shlomifish.org/ The Case for File Swapping - http://shlom.in/file-swap Bzr is slower than Subversion in combination with Sourceforge. ( By: http://dazjorz.com/ ) -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: capture error - the better way?
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/
Re: capture error - the better way?
Xiao Lan (小兰) wrote: eval $x=12/0; if ($@) { print 0 div error }' 0 div error Don't rely on testing $@, simply because it is a global variable that can get changed everywhere. Instead, test the return value of the eval itself. (Don't forget to let it return 1 for success, just like with modules.) Avoid string-eval whenever possible. perl -wle ' my $y = 0; if ( !eval { 42 / $y; 1 } ) { my $error = $@ || unknown; print $error; } ' Illegal division by zero at -e line 3. -- Ruud -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/