Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

namespace craziness

by mkmcconn (Chaplain)
on Jan 30, 2001 at 07:41 UTC ( [id://55172]=perlmeditation: print w/replies, xml ) Need Help??

There are discoveries at every bend on the road to Perl enlightenment. One of the most distracting of these, for me, has been Perl's complex and diverse kinds of namespaces.

I came up with the following simple snippet, when I was experimenting to train myself to recognize (mostly-)namespace gotchas. Seasoned monks may not find this very surprising or interesting, but if you're new as I am, I think it's worth meditating on.

Read this closely:
Updated with comments.

#!/usr/bin/perl -w use strict; package First; # set the symbol: MULTIPLIER # and make $x equal to its value. use constant MULTIPLIER => 5*5; my $x = MULTIPLIER; package Second; # set a new symbol: if $x is defined in this context, # make this MULTIPLIER the same as the first, # otherwise "2". use constant MULTIPLIER => defined $x ? First::MULTIPLIER : 2; # easy! It's an error...it's 265...it's 50? Find out :-) print MULTIPLIER * $x, "\n";

Do you know what it will print? Do you know where the values came from?
mkmcconn

UPDATE: I just found this, where tilly shows a very similar behavior.

Update:
tilly it wrapped me in another knot, to add your

BEGIN{print MULTIPLIER; print "\n";}
And on the way there, I tried the following with amusing results (which proves tye's point made to me in CB, that the => operator is not just a cute comma:
BEGIN {print MULTIPLIER => "\n";}
And then, this from out of left field:
BEGIN {print MULTIPLIER * sub{return MULTIPLIER}, "\n";} # which really ought to be written as below to get # sane results (real obfuscation value there, # but not really a namespace issue) BEGIN {print MULTIPLIER * &{sub{return MULTIPLIER}}, "\n";}

Hopefully, I wouldn't even think of doing anything like these, in real life. How would you easily know where the whacky numbers are coming from?

Replies are listed 'Best First'.
Re (tilly) 1: namespace craziness
by tilly (Archbishop) on Jan 30, 2001 at 07:49 UTC
    To make tye happy try appending the following to the very end:
    BEGIN {print MULTIPLIER, "\n";}
    Surprised? :-)
Re: namespace craziness
by a (Friar) on Jan 30, 2001 at 09:31 UTC
    Ah, that tilly; for real fun, move the BEGIN {print MULTIPLIER; print "\n"} down through the code; first before everything (trouble: MULTIPLIER as file handle). Then after first use constant (gets you '25') then after package second ('nother file handle mistake), finally after (or right before)   print MULTIPLIER * $x, "\n";, get's you '2'

    a

Re: namespace craziness
by chipmunk (Parson) on Jan 30, 2001 at 21:10 UTC
    After being surprised by the output, I realized that this really isn't a namespace issue at all. Rather, it's a compile time/runtime issue.

    Both use constant statements are executed at compile time, but the assignment to $x doesn't happen until runtime. When the second use constant is executed, $x is not yet defined, so Second::MULTIPLIER gets the value 2.

    At runtime, $x is assigned the value of MULTIPLER in the First package, which is 25, and then multiplied by the value of MULTIPLIER in the Second package, which is 2.

    Try this variation, where $x is assigned at compile time:

    #!/usr/bin/perl -w use strict; package First; use constant MULTIPLIER => 5*5; my $x; BEGIN {$x = MULTIPLIER}; package Second; use constant MULTIPLIER => defined $x ? First::MULTIPLIER : 2; print MULTIPLIER * $x, "\n";

      Great catch, chipmunk! I see that it is a compile-time issue in the assignment of a value to the constant. Yet, in which namespace is that assignment to $x happening? It's not in "package First" - the $x in the BEGIN block is a global (note no need for use vars: readers could try testing for defined $First::x in the ternary to see what I mean.

      What fun! so, let's turn this into a compounded namespace+compile-time (follow the $x) problem, by re-writing the puzzle like this :

      #!/usr/bin/perl -w # version chipmunk * .04 use strict; package First; use constant MULTIPLIER => 5*5; my $x = MULTIPLIER / 25; BEGIN {$x = MULTIPLIER}; package Second; use constant MULTIPLIER => defined $x ? First::MULTIPLIER : 2; print MULTIPLIER * $x, "\n"; # now what will it print? __END__

      Update
      more good points, chipmunk. I think that each element is a red-herring: the special effects of use constant;, my(), and package in these snippets, all highlight how important it is to understand the context of what's happening in the program, where and when. Thanks for your help in thinking through the issues further.
      mkmcconn

        $x was declared with my, so it is a lexical variable and not in any namespace/package. The package declarations are really a red herring in this code. Compare these similar scripts:
        #!/usr/bin/perl -w use strict; use constant FIRST => 25; my $x = FIRST; use constant SECOND => defined $x ? FIRST : 2; print SECOND * $x, "\n"; __END__
        #!/usr/bin/perl -w use strict; use constant FIRST => 25; my $x ; BEGIN { $x = FIRST; } use constant SECOND => defined $x ? FIRST : 2; print SECOND * $x, "\n"; __END__

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://55172]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-04-17 16:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found