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

This is a really weird problem. I have been trying to use eval to generate hashnames at runtime and it hasn't been working properly - it sees package variables but not lexically scoped variables that are declared outside the current function. However, if I reference the lexical then it seems to see it. Here's an example. The following shows an empty array:
my $code = 'use Data::Dumper; print Dumper \%serial_of;'; eval $code;
However, this next code shows two copies of the hash correctly;
use Data::Dumper; print Dumper \%serial_of; my $code = 'use Data::Dumper; print Dumper \%serial_of;'; eval $code;
Any other reference to the hash also seems to let eval see it correctly. Obviously this is a problem since if I knew the names of the hashes in advance, I wouldn't need to use eval in the first place. This code is being run in conjunction with Damian Conway's Class::Std module, which may or may not make a difference (if it does, I don't see how).

Replies are listed 'Best First'.
Re: Eval doesn't see lexicals
by tilly (Archbishop) on Nov 02, 2005 at 02:22 UTC
    You need to include more details or we can only guess at what is meant.

    Here is an example of a guess.

    sub will_not_be_a_closure { my %serial_of = @_; return sub { eval 'use Data::Dumper; print Dumper \%serial_of;'; } } will_not_be_a_closure(foo=>"bar")->();
    The problem is that when will_not_be_a_closure exits, Perl sees no references to %serial_of and so cleans it up. This is known behaviour and the last I heard it is unlikely to change.

    The solution is to use that variable in any trivial way in the subroutine so that you still have a reference to it. If you use all of the variables that you might use in trivial ways, they will all be there and the eval will find the ones that you want. Like this:

    sub will_be_a_closure { my %serial_of = @_; return sub { my $x = $serial_of{x}; eval 'use Data::Dumper; print Dumper \%serial_of;'; } } will_be_a_closure(foo=>"bar")->();
    Note that in general if you need to use closures and eval, it is better to try to use eval to generate closures rather than to call eval from within a closure. (I know, there are plenty of cases where you can't feasibly do this. But if you can...)

    Two random tips on eval. First, it is good when you use eval to be in the habit of always checking $@ afterwards. Even for trivial evals. Secondly go to the very bottom of perlsyn and read about Plain Old Comments (Not!) and use that change the usual (eval 666) in error messages into something useful (or at least greppable in your source to find the source of the failing eval).

      Okay, I think I understand.

      Variables that perl doesn't see being used get cleaned up when going out of scope. The variables go out of scope when the end of the file is reached which is why the code malfunctions when in a separate file.</>

      I take it that variables still hang around at the start of a new package even though they are no longer directly acessible ( I am supposing that putting { and } around the entire package would change this, at least the samples for Class::Std do it, and there would have to be a reason.)

      It makes sense, but it's pretty obscure ... thanks to all for your input.

        Mostly right.

        The quibble is that I strongly suspect some confusion about how lexical scope works. Coping with Scoping may clarify that. In short, a package declaration affects global variables, not lexical. So lexical variables in scope remain in scope across the package declaration. Like this:

        my $foo = "bar"; package Baz; print "$foo\n"; # prints bar
        Hence the braces as done in the examples for Class::Std serve the purpose of making lexical scope match package scope. Which is important when you're going to want separate lexical variables with the same name.
        I take it that variables still hang around at the start of a new package even though they are no longer directly acessible ( I am supposing that putting { and } around the entire package would change this, at least the samples for Class::Std do it, and there would have to be a reason.)
        No, source code files are already treated as if they were surrounded by { and }, and variables are normally freed at the end of executing the included file. If a sub in that file captures the variable, then its lifetime is extended, but only that sub can subsequently access the retained value. For example:
        # Foo.pm my $var = 1; sub a { eval '$var' # sees an undefined value when later called } sub b { $var; eval '$var'; # sees 1 because b() has captured $var }
        Note that the variable's lifetime is extended merely by the existence of b(), but even with the existence of b(), a() cannot see the variable.

        Dave.

Re: Eval doesn't see lexicals
by BUU (Prior) on Nov 02, 2005 at 01:14 UTC
    Ignoring your stated question (mostly because you didn't providing enough code for me to easily replicate the problem), it seems like your main problem isn't eval and lexicals, it's the hideous design that requires you to use eval to create or access variables. If you really want dynamically named access to a chunk of data, use a hash, that's what its there for.

      Perhaps the main problem is trying to use inside-out objects. I would use a hash otherwise. I have previously used fields to enforce a set of keys, however I understand they are deprecated so I was seeking an alternative. I like the concept of inside-out objects, however there's no easy way to walk the keys. I also wanted to keep the keys in order for outputting a record so a straight hash wouldn't be enough anyway.

      Design considerations aside, I have been banging my head against this code for a little while. It would be nice to know why eval is choosing to ignore a lexical until it is named, unfortunately when I try to boil it down to a simple test case, it works, so I am obviously removing the problem as well, and I am not at liberty to post the code I am working on.

      Thanks for the reply, anyway

        It would be nice to know why eval is choosing to ignore a lexical until it is named...

        That's because Perl doesn't know (at compile time) whether the eval will run nor what it will contain, so it really can't bind to the appropriate lexical. One way to solve this may be to have every scope containing a string eval to bind every lexical in every parent lexical pad, but wow, what a cost.

        It would surprise me if dave_the_m weren't along here shortly to give more details, especially where I started waving my hands over the details.

        package EvilEval; use Class::Std; sub _serial() { '1234567890' }; my %serial_of :ATTR; sub BUILD { my ( $this, $ident, $arg_ref ) = @_; $serial_of{$ident} = _serial(); } sub evil { #use Data::Dumper; print Dumper \%serial_of; my $string = 'use Data::Dumper; print Dumper \%serial_of'; eval $string; } 1;
        Meanwhile, in a nearby perl script ...
        use EvilEval; my $evil = EvilEval->new(); $evil->evil();
        This demonstrates the problem, at least on my setup. If all the code is in the same file there is no problem - even if it is declared in different packages. When the caller is in a different file, the problem occurs.
Re: Eval doesn't see lexicals
by rir (Vicar) on Nov 02, 2005 at 02:18 UTC
    Again you aren't giving enough context to get good help--but single quotes??!

    Be well,
    rir