Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

SOLVED: Eval not trapping fatal error

by Ea (Chaplain)
on Dec 07, 2015 at 12:03 UTC ( [id://1149568]=perlquestion: print w/replies, xml ) Need Help??

Ea has asked for the wisdom of the Perl Monks concerning the following question:

I've got a Houdini of an error here. The Camel Book says that this is how you trap fatal errors, BUT IT ESCAPES!

I was testing that constants were really constants as suggested in a review by Neil Bowers and the following doesn't compile.

use constant PI => 3.14; eval { PI = 3; }; warn "You can't round down PI to 3" if $@;
and the execution aborts with Can't modify constant item in scalar assignment

I've tried it on perls v5.16.3 and v5.18.4 on linux. Any suggestions on what is going on here? Have I missed something?

Sometimes I can think of 6 impossible LDAP attributes before breakfast.

http://act.yapc.eu/lpw2015/ It's that time of year again!

Replies are listed 'Best First'.
Re: Eval not trapping fatal error
by Corion (Patriarch) on Dec 07, 2015 at 12:07 UTC

    Perl cannot compile your code because it is invalid. You cannot assign to a constant or function (unless that function is already known as lvalue subroutine).

    If you want to convert a "syntax"/semantic error to runtime, you will need to use the string form of eval.

      Of course, you're right.

      So, while other constant modules may die and be trapped with eval BLOCK, the constant pragma makes assignment a syntax error and needs to be trapped with eval EXPRESSION. Now I understand the line in the book

      the code in the BLOCK has to be valid Perl code to make it past the compilation phase
      Thanks

      Sometimes I can think of 6 impossible LDAP attributes before breakfast.

      http://act.yapc.eu/lpw2015/ It's that time of year again!

        I don't think that you can trap other constant modules with a block eval either. The issue lies with Perl, which doesn't allow a function/subroutine on the left-hand side of an assignment, unless that function is already known as assignable through the :lvalue attribute:

        > perl -wle "sub foo {}; eval { foo()='baz' }" Can't modify non-lvalue subroutine call in scalar assignment at -e lin +e 1, near "'baz' }" Execution of -e aborted due to compilation errors.

        Marking the subroutine with :lvalue lets Perl know that we intend to let the function appear on the left-hand side of an assignment:

        > perl -wle "sub foo:lvalue {}; eval { foo()='baz' }"

        All "constant" modules are syntactic sugar for defining functions that take no parameters, because that's how sigil-less constants work in Perl.

Re: SOLVED: Eval not trapping fatal error
by kcott (Archbishop) on Dec 07, 2015 at 20:32 UTC

    G'day Ea,

    I see ++Corion has given plenty of information on why you can't assign to a constant.

    Constants, such as the PI you have in your code, are subroutines with a prototype of '()' which allows them to be inlined (see "perlsub: Constant Functions"); as such, they can be redefined.

    I really don't recommend that you use the following in any production code but, purely as an academic exercise, consider this:

    #!/usr/bin/env perl use strict; use warnings; use constant PI => 3.14; eval { no warnings 'redefine'; sub PI () { 3 } }; warn "You can't round down PI to 3" if $@; print 'PI now set to ', PI, "\n";

    When run, this outputs:

    PI now set to 3

    No errors or warnings are emitted.

    — Ken

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1149568]
Approved by Athanasius
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (8)
As of 2024-04-25 11:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found