ASPN ActiveState Programmer Network
ActiveState
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups


Recent Messages
List Archives
About the List
List Leaders
Subscription Options

View Subscriptions
Help

View by Topic
ActiveState
.NET Framework
Open Source
Perl
PHP
Python
Tcl
Web Services
XML & XSLT

View by Category
Database
General
SOAP
System Administration
Tools
User Interfaces
Web Programming
XML Programming


MyASPN >> Mail Archive >> perl5-porters
perl5-porters
Re: Ignorant wumpus? Or scoping problem?
by Glenn Linderman other posts by this author
Nov 26 2003 10:23PM messages near this date
Re: [patch pod/perlref.pod] (was Re: Ignorant wumpus? Or scoping problem?) | Re: Ignorant wumpus? Or scoping problem?
On approximately 11/26/2003 2:38 AM, came the following characters from
the keyboard of Dave Mitchell:
>  On Tue, Nov 25, 2003 at 02:10:00PM -0800, Glenn Linderman wrote:
>  
> >1) Do the initial "use strict" and "use warnings" apply to the eval'd
> >code
>  
>  
>  Yes, they are lexically scoped, eg
>  
>  $ perl -e 'use strict; eval q{$x=1}; print $@'
>  Global symbol "$x" requires explicit package name at (eval 1) line 1.

Thanks for the clarification.  This is what I thought happened, but when 
I ran into the other problems I began to wonder.

> >2) The variables of interest are all lexicals in the scope of the
> >closure where function foo is defined... $scaler, @array, and %hash.
> >The functions, with strict and warnings enabled, seem to compile fine.
> >But when function eval_printall runs, the variables seem to all be
> >undefined
>  
>  
>  Closures work at follows: when a sub is created, it captures the currrent
>  instances of any lexical variables that are referred to inside the sub,
>  but which are delcared outside that sub. The use of eval often delays this
>  capturing, so that the required lexicals are no longer available.
>  
>  eg this simple example:
>  
>  
>      {
>  	my $x = 1;
>  	sub f1 { print "f1: x=$x\n" }
>  	sub f2 { eval 'print "f2: x=$x\n"' }
>      }
>  
>      f1;
>      f2;
>  
>  produces the following output:
>  
>  f1: x=1
>  Use of uninitialized value in concatenation (.) or string at (eval 1) line 1.
>  f2: x=
>  
>  What happens here is that when f1 is compiled, the compiler notices that
>  the sub f1 makes mention of the outer lexical $x, so f1 gets its own
>  private reference to that variable. When f2 is compiled, it has no such
>  mention of $x, so it doesn't also capture $x.

A follow-on question here: when f1 gets its own private reference to $x, 
I'm assuming that it would still share the value with any other subs 
defined in that block that would also reference $x.  That is, that each 
such sub would get its own reference, but only one value would exist, 
and the subs could communicate through that variable if they chose to. 
Experimentally, this seems to be the case.

>  After the { } block is exited, the interpreter disacards the current (and
>  only) instance of $x. When f1 is later called, it still has its private
>  copy of $x, and so can print out its value. When the eval is compiled via
>  f2, f2 hasn't got a private copy of $x, so the eval tries to grab the
>  value of the 'real' $x, which is now undef.
>  
>  In the current development version of perl, you actually get a warning
>  when this happens:
>  
>  f1: x=1
>  Variable "$x" is not available at (eval 1) line 1.
>  Use of uninitialized value in concatenation (.) or string at (eval 1) line 1.
>  f2: x=

OK, this warning sure would have been helpful to my understanding this 
issue... in fact, why is it only a warning, instead of an error... if 
the variable really doesn't exist, and use strict is in effect, should 
it not be an error?  Although, I'd rather have it work, as you can read 
below....

>  The moral of this tale is to be careful with evals. They often do funny
>  things because the compiler can't know in advance what the eval might
>  contain.

Sure, I understand the compiler can't know in advance what the eval 
might contain.... but I guess I would have expected, from comments in 
the Camel about eval being evaluated in the lexical context where the 
eval call appears, that the variables in the surrounding block would be 
available.

It seems like it would be possible to make it work that way, and that 
working that way would produce more useful results.

The corresponding cost of doing so would seem to be that instead of a 
function squirrelling away a reference to the variables it uses to make 
the closure, that it would squirrel away a reference to the whole 
collection of lexicals (do they call that the pad?) available at the 
scope of its definition.  Yes, this would cost more in memory 
consumption if only a few variables are referenced but many defined... 
on the other hand, one doesn't normally define subs inside blocks 
containing lexical variables, unless the intention is to define a 
closure... and if one is defining dozens or hundreds of subs within that 
closure (as I am doing), saving the reference to the whole collection 
might actually save space.  And if one is defining dozens or hunders of 
subs within that closure by executing "eval" with a function in that 
closure, it would have a much better chance of doing The Right Thing for 
those eval'd functions.

So I suppose one _could_ implement both techniques, the current one of 
just saving the referenced variables, and my suggested one, of saving 
everything, perhaps turning from one technique to the other via a 
pragmatic module... or heuristically, switching to saving everything for 
any function that contains an eval, so that everything would be there 
for the eval'd code to reference.

Does anyone think this behavior of Perl/closures/evals is a bug?  One 
that is worth fixing?  Or even possible to fix as outlined above?  Or 
that will ever get fixed?  Or possibly even documented better, so the 
trap can be avoided?  The warning in the development version does help 
with avoiding the trap, I guess.  I guess the fact that the warning was 
added implies that someone besides myself was surprised by the current 
behavior....

For the moment, I've chosen the workaround of moving all the variables 
that I intended to have inside the closure, into global space.  This 
caused a few naming collisions, which I was able to resolve fairly 
quickly, because all the source code of concern was authored by me :) 
This workaround, based on your helpful explanation, is, in fact, a 
complete 100% cure for the issue... but it suffers a bit in modularity 
vs the intended collection of functions sharing the variables of a 
closure.  I suppose an alternative solution would be to wrap a different 
package around those definitions, which would give me a 2nd global scope 
to contain those variables, which would have avoided the naming 
collisions, but also forced me to prefix calls to each of the hundreds 
of functions defined in for the package with the package name (or to 
export them all).

-- 
Glenn -- http://nevcal.com/
===========================
Like almost everyone, I receive a lot of spam every day, much of it
offering to help me get out of debt or get rich quick.  It's ridiculous.
-- Bill Gates

And here is why it is ridiculous:
  The division that includes Windows posted an operating profit of $2.26 
  billion on revenue of $2.81 billion.
  --from Reuters via 
http://biz.yahoo.com/rc/031113/tech_microsoft_msn_1.html

So that's profit of over 400% of investment... with a bit more 
investment in Windows technology, particularly in the area of 
reliability, the profit percentage might go down, but so might the bugs 
and security problems?  Seems like it would be a reasonable tradeoff. 
WalMart earnings are 3.4% of investment.
Thread:
Glenn Linderman
Dave Mitchell
Stas Bekman
Brad Baxter
Stas Bekman
Dave Mitchell
Stas Bekman
Glenn Linderman
Dave Mitchell
Glenn Linderman
Dave Mitchell
Glenn Linderman
Brad Baxter
Brad Baxter
Glenn Linderman
Dave Mitchell
Rafael Garcia-Suarez
Glenn Linderman
Stas Bekman
Glenn Linderman
Alan Burlison

Privacy Policy | Email Opt-out | Feedback | Syndication
© ActiveState Software Inc. All rights reserved