[Phoenix-pm] Eval Namespace Question

Scott Walters scott at illogics.org
Mon Aug 7 15:08:50 PDT 2006


Hi Doug,

So, what *have* you been up to?

Don't use eval on a string.  eval { } is fine to use and you should be
trapping errors, and that's how that's done.  99% of the time people use
eval on a string, they're trying to hammer in a screw.

> This means that in my code below, that $bar is in scope within the 
> eval.  What blows me away is that $foo::foo is also in scope because of 
> the "package foo" statement in $eval_string.  Does anyone know how perl 
> 
> #!/usr/bin/perl
> package foo;

Use strict and warnings.

> $foo = "FOO!";

> package bar;
> my $bar = "BAR!";
> my $perl_code = 'print "$bar $foo\n"';
> print "$perl_code\n";
> 
> my $eval_string = "package foo;\n$perl_code";
> eval $eval_string;

To answer your actual question, variables created (defined implicitly or explicitly)
at the "top level" (outside of any blocks) have a scope called "file scope", where
they're in scope until the end of the file.  This would work with my $foo too.
Sometimes people do this to get less scope than file scope:

package foo; {
    my $foo = "FOO!";
}

package bar; {
  ...
}

There are other derivitives of out.

Now, here's what you *should* be writing to avoid a plague of security and
performance problems too numerous to enumerate and too pervasive to ignore
the shame they've brought upon us all:

package foo;
use strict;
use warnings;
my $foo = "FOO!";

package bar;
# note that strict and warnings also have file scope
my $bar = "BAR!":
my $perl_code = sub { print "$bar $foo\n"; };
$perl_code->(); # note that you could pass arguments

In this adaptation, you can't easily modify the code by prepending things
like "package foo;", but dataflow is an entire other question.  Rather than
changing packages that code evaluates in, you should be passing objects in,
and the object should encapsulate the set of values.  Also, with code references,
if the code reference references some variable (such as $foo and $bar), if
the value of $foo or $bar changes (the *same* $foo or $bar, not one 
created later or in a different scope) then the value that gets printed
also changes.  

So...

1. use code references instead of eval
2. use object instances rather than packages full of global values
3. when you want a global of some sort, use the constant module... use constant foo => 'FOO!';
4. report to the list more often and tell us how your life is going
   and what you're up to, for chrissakes!

As far as the "use objects" spiel... I'm assuming the worst, so forgive me for that, but
in my experience, the not-so-bad-scenario can usually be considered to be similar enough
to the bad scenario that the refactoring/best practice/design heuristic/whatever
still applies.  Computing package names on the fly invokes fear and dread for good
reason and should only be used to intentionally voke fear and dread.  Etc, etc, etc.

Glad to see you're still alive, Doug.

-scott



> 
> _______________________________________________
> Phoenix-pm mailing list
> Phoenix-pm at pm.org
> http://mail.pm.org/mailman/listinfo/phoenix-pm


More information about the Phoenix-pm mailing list