Re: question about variabies/references (ignore my previous botched entry)
by plaid (Chaplain) on Apr 05, 2000 at 12:31 UTC
|
This has to be one of the best questions I've seen here, if only for the reson
that it gave me a good chance to go digging around and try to figure this
out. This explanation is far from perfect and any additions/corrections
are welcome.
The main problem comes with the line $main::{$test} = "skot2". This is
a lookup into the symbol table of main::, with the key of $test. Perl
stores its symbol table in the form of string keys, and typeglob values.
$main::{$test} is not the same as the $$test a couple lines down, but rather
is the same as $::{$test}.
As for the weirdness in the last line, with $scott and $skot2 now being the
same value, the $main::{$test} = "skot2" line again needs to be looked at.
The main:: symbol table is expecting a typeglob or a reference on assignment,
but when perl is expecting a typeglob and gets a string, it automatically
creates a new typeglob of that name, so that line is functionally equivalent
to having put $main::{$test} = *skot2. This is effect creates an alias
between $scott and $skot2, so changes to either one will affect the other.
What needs to be done to get any kind of sensible answer is to pass in a
reference on the assignment to $main::{$test}. There are two ways to go
about it. Either you can do $main::{$test} = \"skot2", which will make the
value of $scott come out right, but will make it be a constant, and thus
the assignment to $$test will fail. The better way to do it would be to
assign the value "skot2" to another variable, and pass in the reference of
that variable.
Hope this helps. | [reply] |
Re: question about variabies/references (ignore my previous botched entry)
by chromatic (Archbishop) on Apr 05, 2000 at 19:04 UTC
|
Here's a funny thing. $scott and $main::scott refer to the same variable, assuming you haven't declared that you're in another package. Another piece of the puzzle is that putting curly braces around anything that looks like a variable causes Perl to interpolate the value of that variable. Doing:
$main::{$test} = "skot2";
first causes interpolation -- so that the interpreter now has:
$main::scott = "skot2";
From there, I assume plaid is correct in that the interpreter decides that you really meant to do a typeglob assignment, and takes "skot2" to be a symbolic reference (that is, the name of another variable). Since it hasn't been declared before, $scot2 (and $main::scot2) are autovivified. Next, $main::scott is aliased to $scot2.
The $$test line is even more tricky. You might also write it
${$test} = "surprise!";
to be consistent with my explanation. If $test were a normal reference, this would dereference it. Since it contains the name of a variable ($skot2 has just been created automatically), Perl considers it a symbolic reference, looks up $main::skot2 in the symbol table, and assigns the value of "surprise!" to it.
Because $main::scott is aliased to $skot2, accessing it gets you the same value ("surprise!"). Because you're in package main, you can leave off the $main:: portion, and accessing $scott also gets you your "surprise!".
These are three or four things that will eventually surprise any new Perl programmer. Using strict and -w will warn you when these things happen (except for autovivification in hashes, which is worth another page of explanation). Use them liberally! | [reply] [d/l] [select] |
|
> Another piece of the puzzle is that putting curly
> braces around anything that looks like a variable
> causes Perl to interpolate the value of that
> variable. Doing:
>
> $main::{$test} = "skot2";
>
> first causes interpolation -- so that the
> interpreter now has:
>
> $main::scott = "skot2";
No, I don't think this is true. When you do
$main::{$test} = "skot2";
you're manipulating the symbol table of package main;
this is a very different thing than modifying a scalar
variable ($main::scott). $main::scott and $main::{"scott"}
are two different things.
| [reply] [d/l] [select] |
|
You're right, the post-interpolated line should read:
*main::scott = "scot2";
Here's what I've been using to test my assumptions:
#!/usr/bin/perl
$test1 = "value of test1";
$test2 = "test1";
$test3 = "Why are you here?";
# refers to *main::test1
print "=>$main::{$test2}<=\n";
print "Original \$test1: ...$test1...\n";
$main::{$test2} = "test3";
# $main::{"test1"} = "test1";
print "\$test1 = >>", $test1, "<<\n";
print "Main package: ", $main::test1, "\n";
As you can see, $main::{$test2} evaluates to a typeglob.
Saying that $main::{$test2} = "test3" changes the scalar is technically incorrect. (Though it is what my previous answer would lead one to believe!)
Dunno where that u came from. Maybe it's a mu? | [reply] [d/l] [select] |
|
Re: question about variabies/references (ignore my previous botched entry)
by btrott (Parson) on Apr 05, 2000 at 20:05 UTC
|
You're seeing this weird behavior because you have several
variables that point to the same
value; at the time of the first print, you haven't yet
set that value, so it's undefined. When you set the value
in the next line, it sets that value, so when you do the
second print, they have a value.
Let's step through it:
$test = "scott";
This is self-explanatory--you're just setting a scalar
variable. Later you'll use that value as a symbolic
reference.
$main::{$test} = "skot2";
Here you're manipulating the symbol table; you're saying
that $main::scott should point to the same thing that
$main::skot2 points to. You can do this symbol table
manipulation quite easily, and there's a definite potential
for confusion--for example, there's a difference between
$main::{"scott"} and $main::scott. The first is a symbol
table entry and the second is a scalar variable.
print "As you see, ($scott) and ($main::scott) " .
"aren't here\n";
$scott and $main::scott are the same variable, because
$scott is found in package main, and the second is just
a fully-qualified version of the first. You haven't set a
value for this variable yet. You've modified
$main::{"scott"} but not $main::scott. Perhaps that's
the real source of your confusion?
$$test = "surprise!";
Here's where you set the value. $test is equal to "scott",
so here you're just using symbolic references to change
the value of $scott (which is the same as $main::scott
and points to $skot2). So, it makes sense that, in the next
line...
print "Now ($scott) and ($skot2) and ($main::scott) " .
"have decided to show up\n";
you now have values for your variables.
Does this make sense?
| [reply] [d/l] [select] |
Re: question about variabies/references (ignore my previous botched entry)
by jbert (Priest) on Apr 05, 2000 at 14:00 UTC
|
Its perl's way of reminding you that symbolic references are evil.
Don't do that. (Unless of course you want to)
-w and use strict, all the way. | [reply] |