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

Hi PerlMonks,

Instead of exporting a package variable I intended to return the value via 'eval' in a module function. Surprisingly the value is just returned, if I also access the variable 'natively'

Module:

package MyModule2; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(func3 func4); %EXPORT_TAGS = ( DEFAULT => [qw(&func3)], All => [qw(&func3 &func4)]); my $myscalar = "MyScalarValue"; sub func3 { my $x; my $y; printf "MyModule2/func3: >%s<\n",$_[0]; $x = eval "$_[0]"; return $x; } sub func4 { my $x; my $y; printf "MyModule2/func4: >%s<\n",$_[0]; $x = eval "$_[0]"; $y = $myscalar; return $x; } 1;

script:

#!/usr/bin/perl -w use strict; use MyModule2 qw(:All); printf "MyScript2/func3: >%s<\n",func3('$myscalar'); printf "MyScript2/func4: >%s<\n",func4('$myscalar');

output:

perl MyScript2.pl MyModule2/func3: >$myscalar< Use of uninitialized value in printf at MyScript2.pl line 7. MyScript2/func3: >< MyModule2/func4: >$myscalar< MyScript2/func4: >MyScalarValue<

is there any explanation for this behaviour?

Replies are listed 'Best First'.
Re: eval in perl package
by Eily (Monsignor) on Mar 01, 2018 at 14:44 UTC

    Well, func4 is a closure. Perl sees that it uses a lexical variable from its declaration scope, so it keeps a link to that scalar value for the function to still be able to access it (and to prevent the scalar from being deleted at the end of the file). func3 holds no such link. Now I don't know what variable func3 acccesses, because the eval doesn't fail, but calling eval "$_[0]++" always returns 0 so it's not always the same var.

    Instead of exporting a package variable I intended to return the value via 'eval' in a module function.
    Honestly that sounds like a bad idea. Maybe you can use a hash instead.

      > Perl sees that it uses a lexical variable from its declaration scope, so it keeps a link to that scalar value for the function to still be able to access it

      To elaborate further, each sub (and each block?) has hash like structures called "Pads", where closed over variables are referenced.

      This Pad is filled at compile time, and eval can only access lexical variables used in this scope.

      PadWalker allows to inspect this pad, or the pad of surrounding scopes.

      (PadWalker could also be used as a workaround for the OP)

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Wikisyntax for the Monastery

Re: eval in perl package
by Eily (Monsignor) on Mar 01, 2018 at 15:12 UTC

    Actually, if you want to export later (and not just return the value). Just add your variable as a package variable, and export it in @EXPORT_OK. Then you can either write: use MyModule2 '$ourscalar', or if you want to export it later:

    use MyModule2; #only exports defaults ... #some code MyModule2->import('$ourscalar');
    use actually calls import right after require, except it is down at compile time rather than during execution.

Re: eval in perl package
by hippo (Archbishop) on Mar 01, 2018 at 14:47 UTC
    is there any explanation for this behaviour?

    Yes. func4 is a closure but func3 is not.

Re: eval in perl package (updated getter %exported_lex) )
by LanX (Saint) on Mar 01, 2018 at 14:20 UTC
    Prelude

    I stand corrected, Eily and hippo are right, the sub can only see closed over variables, I didn't try the code, mea culpa

    update end

    I don't understand your question, what is natively supposed to mean?

    Both func return the same $x.

    $y = $myscalar; is the only important but non effective difference.

    update getter

    the straightforward way to implement this is an exported getter

    sub get_myscalar { return $myscalar }

    If you really have too many individual lexicals to be handled by getters, you probably want to hold them in a hash instead.

    update %exported_lex

    my %exported_lex ={ myscalar => \$myscalar, myscalar2 => \$myscalar2, } sub get_lex_ref { return $exported_lex{$_[0]} } sub get_lex_val { return ${$exported_lex{$_[0]}} }

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Wikisyntax for the Monastery

      Hi Rolf

      with 'natively' I meant that I use variable &myscalar explicitely and not just indirectly in the eval statement. When reading all comments I suppose the correct wording would be "in lexical context"

      Thanks to all for explanation and background information.

      Cheers Marcus

        Hello Marcus,

        Welcome to the monastery!

        And your code is an excellent example to demonstrate how closures internally work.

        Thanks! :)

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Wikisyntax for the Monastery