in reply to Not-so-lazy evaluation?

$i is not declared when your string is eval()d and you're not testing if the eval succeeds:

use strict; use warnings; #return a pointer to a function that should be invoked sub makeLazy { my ($inp) = @_; sub { eval $inp; die if $@; }; } my $i = 1; my $part2 = makeLazy('print "\nnow its $i";'); print "\ni is ".$i++; $part2->(); print "\ni is $i";
Global symbol "$i" requires explicit package name at (eval 1) line 1. ...propagated at test.pl line 8.
Why are you not just doing
use strict; use warnings; my $i = 1; my $part2 = sub {print "\nnow its $i"; }; print "\ni is ".$i++; $part2->(); print "\ni is $i";

Replies are listed 'Best First'.
Re^2: Not-so-lazy evaluation?
by mtroost (Initiate) on Nov 06, 2007 at 16:33 UTC
    > $i is not declared when your string is eval()d
    That baffles me. At compile time, perl is just having a string. It is at run time, when the execution reaches the $part2->(); statement that the string is evaled inplace and the string is compiled and evaled. At that point in time, $i should be declared (initial post , perl codelisting 2) in my newbie opinion.

    Basically that opinion shows faulty but questions still remains. When is $i evaled? Or in what dictionary/environment/whatever-mechanism-is-used?

    The value of $i that is printed (in the first perl program) is the value that i was expecting IF it was evaled at the line $part2->(); It looks to me like there is a mismatch between the places where it is defined and where it is executed. I am assuming this to be the same place. If it is at the place of definition of makeLazyFunction, then i expect $i to have the value 1 and not 2. If it is at the place of $part2->(), then i expect $i to have the value 2 and to be defined as well. Are both views erroneous? What is the correct view?

    > Why are you not just doing
    Because of the same problem i run into with my code (but i didnt knew until now that it was the same problem): if you defer the declaration of $i then you get Global symbol "$i" requires explicit package name at test1.pl line 7. Only with my code it doesnt show because the error is only generated at run-time and is not printed. No printing, no error i was thinking, alas mistakenly.
      > $i is not declared when your string is eval()d That baffles me. At compile time, perl is just having a string. It is at run time, when the execution reaches the $part2->(); statement that the string is evaled inplace and the string is compiled and evaled. At that point in time, $i should be declared (initial post , perl codelisting 2) in my newbie opinion.
      Lexical variables (such as my $i), are, um, lexically scoped.

      When the eval tries to compile the code and sees a $i, it scans out through the lexical scopes looking for a matching $i declaration. This scanning starts at the physical location of the eval itself within the text. ie it looks for my $i in the text of the eval string (somewhere before the $i), then in the text of the anon sub (somewhere before the eval), then in the text of the makeLazy sub (somewhere before the anon sub definition), then in the main body of the file itself (somewhere before the makeLazy definition).

      Since it doesn't find a lexical $i delaration in any of those scopes, it assumes you meant the package variable $i, which then gives an error under strictures.

      Dave.

      Basically that opinion shows faulty but questions still remains. When is $i evaled? Or in what dictionary/environment/whatever-mechanism-is-used?

      In your case, $i is evaluated when the string containing a literal '$i' is eval()ed. You could evaluate $i earlier by interpolating $i into the string (evaluating $i when the string is created), but then, that would convert the value of $i into a string, which isn't always what you want:

      makeLazy(qq(print "\nnow its $i"));
      Note that this also decouples the eval'd code in makeLazy from the actual current value of $i.

      Because of the same problem i run into with my code (but i didnt knew until now that it was the same problem): if you defer the declaration of $i then you get Global symbol "$i" requires explicit package name
      Well, what do you want it to do? Either you want a lexical variable, but then you must declared it in its lexical scope, or you may want a (possibly local()ized package variable) - which you don't have to declare, if you prepend them with the package name (or you *could* switch of strict 'vars').

      update: Note that in my alternative version, using my $defer = sub  { something_with($i) } syntax, $i is evaluated when $defer->() is called, but the scoping of $i is resolved at compile time, and figuring out the actual instance of $i may be resolved when the $defer = .. assignment is executed (that last part is important if you're generating these $defer closures from within another subroutine, with $i declared lexical in the outer subroutine).

      You may find this column useful