http://www.perlmonks.org?node_id=452015

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

Greetings,

I am messing around with eval since it's cool and trying some stuff. I am trying to run something AUTOLOAD like for experimental sake and I cant seem to get this to work.

I looked at the docs and it says that all local and global vars will be defined in the eval space. And on some simpler non OO tests that works fine. What this thing is tossing for an error is that $self is not defined but I did a dump check and it is. Any reason why $self is not being added to the namespace for he eval in the same function that I am missing?

Thanks in advance

The error message: Can't call method "get_user" on an undefined value at (eval 1) line 1.
sub get_function my $self = shift; my $function = shift; my @arguments = @_; my $argument; my $result; my $code = '$result = $self->' . $self->{object_methods}{$function +} . '('; my $has_arguments; foreach $argument ( @arguments ) { $has_arguments = 1; $code .= "\'$argument\',"; } if( $has_arguments ) { chop $code; } $code .= ");"; print $code; eval $code; if( $@ ) { $self->{'error_type'} = "mail_merge_function error"; $self->{'error_string'} = "mail_merge_function error $@"; return( undef ); } else { return $result; } }

Replies are listed 'Best First'.
Re: eval inside an object
by ikegami (Patriarch) on Apr 27, 2005 at 16:47 UTC

    If I understand correct, you code is equivalent to the code below. The difference is that the code below doesn't use eval EXPR which is slow because it must compile the Perl code. The eval BLOCK used below doesn't compile anything; it just catches exceptions.

    sub get_function { my $self = shift; my $function = shift; $function = $self->{object_methods}{$function}; my $result = eval { $self->$function(@_) }; if ($@) { $self->{'error_type'} = "mail_merge_function error"; $self->{'error_string'} = "mail_merge_function error $@"; } return $result; }
Re: eval inside an object
by salva (Canon) on Apr 27, 2005 at 16:43 UTC
    it says that all local and global vars will be defined in the eval space

    $self is not local or global, it's a lexical variable!... though, I recall seing some patch for this in p5p, maybe its supported in the development version of perl (currently 5.9.2).

    Anyway, you don't need eval for what you are trying to do, use

    $method_name="foo"; $self->$method_name(@args);
      $self is not local or global, it's a lexical variable!... though, I recall seing some patch for this in p5p, maybe its supported in the development version of perl (currently 5.9.2).
      The lexical scope bugs I've fixed in the 5.9.x branch aren't applicable here; a simple eval executed immediately (as opposed to later via a closure) has always been able to see variables in its immediate enclosing scope.

      Dave.

Re: eval inside an object
by sir.shz (Novice) on Apr 27, 2005 at 18:00 UTC
    Maybe you need to escape the "$self" as "\$self" since eval will first evaluate the $code, in which case $self will be subsititued by its value, something like "ClassName->HASH(...)". The following seemed to work:
    package Foo; use strict; sub new{ return bless {}, shift; } sub foo{ my $self = shift; print "Foo called\n"; } sub bar{ my $self = shift; print "Bar called\n"; my $code = "\$self->foo()"; # it won't work withouth the "\" eval $code; } 1;
    then:
    use strict; use warnings; use Foo; my $c = Foo->new(); $c->foo(); $c->bar(); __OUTPUT__ Foo called Bar called Foo called
      The OP used single-quotes, so the $ in $self (and in $result) doesn't need to be escaped.
Re: eval inside an object
by g0n (Priest) on Apr 28, 2005 at 09:34 UTC
    Slightly OT, but probably worth mentioning. Eval is indeed cool, but it has its evil side. E.g the following code:

    #code a my $function = $node->{'activationfunction'}; my $functionCall ="\$value = \$network->$function(\$value);"; eval($functionCall); #code b my $function = $node->{'activationfunction'}; $value = $network->$function($value);

    Eval saved me once upon a time from having to learn that code b was possible. BUT, since I was calling this tens of thousands of times in normal program execution, and hence invoking the compiler every time, once I did learn that code b was possible, the program speeded up by several hundred fold!

    The moral - eval is cool, but very very slow!

    g0n, backpropagated monk
Re: eval inside an object
by eyepopslikeamosquito (Archbishop) on Apr 28, 2005 at 12:29 UTC

    I am messing around with eval since it's cool
    Block eval (for exception handling) is cool; string eval is ... luke warm. OK, it is fun, but you should try to avoid it in production code. Quoting merlyn from •Re^2: Dynamically constructed function calls:
    Do not resort to eval-string if other means are available. You're firing up the compiler (slower than almost any other solution), and exposing yourself to hard to debug and hard to secure practices.

    Update: If you want a second opinion, see this quiz of the week where MJD states:

    A good rule of thumb is that unless what you're trying to do is most clearly described as "compile and run arbitrary Perl code", it's probably a mistake to use 'eval' to do it.

    Somewhat related, symbolic references are also evil, as convincingly demonstrated by MJD in three parts: part 1 and part 2 and part 3.

Re: eval inside an object
by moot (Chaplain) on Apr 27, 2005 at 16:34 UTC
    You'll need to provide more information, specifically what does @arguments contain? Some object inside the eval has not been defined.