How do I scope a variable if the variable name contains a variable?

D

David Filmer

I can do this:

my @bar; #explicit name - fine

but not this:

my $foo = 'bar'; #fine
my @{$foo}; #oops

Perl complains, "Can't declare array dereference..."

Does anybody know the syntax to scope a variable name that includes a variable?

Thanks!
 
J

Jim Cochrane

I can do this:

my @bar; #explicit name - fine

but not this:

my $foo = 'bar'; #fine

my @{$foo}; #oops

The above is how you deference a reference, which you can define with,
e.g.:

my $f = [1, 2, 3];

and use, e.g.:

print "@{$f}\n";

or, in this case:

print "@$f\n";

Is this what you're looking for?
 
U

Uri Guttman

JC> my $f = [1, 2, 3];
JC> print "@{$f}\n";
JC> print "@$f\n";

JC> Is this what you're looking for?

he is looking for the evil symrefs, which luckily you didn't provide.

to the OP:

use a hash. see the many threads (google for them) on this. we get this
asked every week.

uri
 
D

DavidFilmer

Uri said:
use a hash. see the many threads (google for them) on this. we get this
asked every week.

Hmmm. Either the question is not asked nearly as often as Uri recalls,
or else my Google search terms are far too general (I get over 1000 hits
with: perl scope variable hash my symref - bad signal to noise ratio).

Anyway, I didn't find the question answered, but one posting I found
mentioned:
perldoc -q 'variable as a variable'
(which is a perfectly natural perldoc topic name, though I would have
never thought of it).

Anyway, it didn't specifically answer this question, but I was able to
figure it out easily enough with Uri's remarks and the perldocs. For the
benefit of those who may Google this posting, I offer this simple-case
solution:

use strict;

my %array; #this is the hash that Uri mentioned
my $foo = 'bar';

@{$array{$foo}} = qw/a b c d e f g/; #or whatever

print @{$array{$foo}}; #same as: @{$array{'bar'}}
 
U

Uri Guttman

D> Hmmm. Either the question is not asked nearly as often as Uri recalls,
D> or else my Google search terms are far too general (I get over 1000
D> hits with: perl scope variable hash my symref - bad signal to noise
D> ratio).

try symrefs or symbolic references or soft references

use the words *I* mentioned.

D> Anyway, I didn't find the question answered, but one posting I found
D> mentioned:
D> perldoc -q 'variable as a variable'
D> (which is a perfectly natural perldoc topic name, though I would have
D> never thought of it).

D> Anyway, it didn't specifically answer this question, but I was able to
D> figure it out easily enough with Uri's remarks and the perldocs. For
D> the benefit of those who may Google this posting, I offer this
D> simple-case solution:

D> use strict;

D> my %array; #this is the hash that Uri mentioned
D> my $foo = 'bar';

D> @{$array{$foo}} = qw/a b c d e f g/; #or whatever

D> print @{$array{$foo}}; #same as: @{$array{'bar'}}


and you fell into the trap of the evil symref. do not go there if you
value your coding career. there lies deamons you don't want to release.

and here is my standard rant on this:

symbolic references use the symbol table to allow the creation and
access to variables with dymamically created names. but the symbol table
is really just a hash tree with special side effects. so why would you
use a specialized hash tree for this when a regular hash would work just
as well? and a regular hash has many advantages. it can be passed around
by reference, it can be stored in a lexical variable, it can be private
(a symbolic ref variable is always global and accessible).

so go ahead, pick the evil way which looks easy but is nasty, or the
nice and clean proper way which is as easy but requires a little
more understanding and will be used much more often.

and my final rules:

don't use the symbol table until you know when to not use it. the symbol
table is for managing symbols, it is not a general purpose data
structure.

uri
 
G

gnari

[about finding answers to one's questions]
Anyway, I didn't find the question answered, but one posting I found
mentioned:
perldoc -q 'variable as a variable'
(which is a perfectly natural perldoc topic name, though I would have
never thought of it).

this just proves once again:
a) put the subject of your article in the Subject of your article
b) one should read the FAQ entirely once in a while, at least
read the questions. the FAQ is a great resource, and it is useful
to be aware of its content.

gnari
 
A

Anno Siegel

Uri Guttman said:
JC> my $f = [1, 2, 3];
JC> print "@{$f}\n";
JC> print "@$f\n";

JC> Is this what you're looking for?

he is looking for the evil symrefs, which luckily you didn't provide.

Not necessarily, though the subject certainly looks like that.

I read the question as: "How can I make the array "@{ $foo}" a lexical
array?". This question makes as much (or as little) sense whether
$foo contains a variable name (symref) or a legit array-reference (hard
ref).

In either case the answer is "You can't". In the case of a symref the
actual array *must* be a package variable, so it can't be a lexical.
But we're not talking about symrefs anyway, are we?

In the case of an arrayref the actual array is anonymous. "Lexical"
pertains to the scope where a variable *name* is valid. Since @{ $foo}
doesn't have a name, the distinction doesn't apply. The scope of an
anonymous variable, if we want to apply the term, would be the scope
of the underlying named variable ($foo in this case). It doesn't
have one of its own.

Anno
 
R

Richard Gration

D> use strict;

D> my %array; #this is the hash that Uri mentioned
D> my $foo = 'bar';

D> @{$array{$foo}} = qw/a b c d e f g/; #or whatever

D> print @{$array{$foo}}; #same as: @{$array{'bar'}}

and you fell into the trap of the evil symref.

Did he? This looks like a plain case of using a variable to hold a hash
key ... ?

Confused, I am. Could you please explain what I'm missing?

Rich
 
S

Sherm Pendley

Uri said:
the symbol table is really just a hash tree with special side effects.

A related question - I recall reading here that Perl has a limit on the
length of its symbols. There seems no logical reason to limit key lengths
for one particular hash tree when others are not limited; does that mean
the limitation is in the parser? Is it a lex issue?

Or did I imagine the whole thing? ;-)

sherm--
 
U

Uri Guttman

D> my %array; #this is the hash that Uri mentioned
D> my $foo = 'bar';
RG> Did he? This looks like a plain case of using a variable to hold a hash
RG> key ... ?

RG> Confused, I am. Could you please explain what I'm missing?

on second thought it does look like hard refs and accidental
autovivification discovery. i just smelled symrefs from the OP and that
code at first glance looked like it was used.

uri
 
R

Randal L. Schwartz

Sherm> A related question - I recall reading here that Perl has a
Sherm> limit on the length of its symbols. There seems no logical
Sherm> reason to limit key lengths for one particular hash tree when
Sherm> others are not limited; does that mean the limitation is in the
Sherm> parser? Is it a lex issue?

It was formerly 255 characters per symbol (between double-colons). It
has now been relaxed (as of Perl 5.6, if I recall). The problem was a
fixed-length buffer in the lexer, so it applied only to literal
symbols, not to symbolic symbols created at runtime. So

$aaaaaa ... 300 total ... aaaa = 1;

was formerly illegal, but (caution symref coming up):

${"a" x 300} = 1;

was legal. Now they both "work" for some definition of work.

print "Just another Perl hacker,"; # the original
 
D

David Filmer

Uri wrote...
D> Hmmm. Either the question is not asked nearly as often as Uri recalls,
D> or else my Google search terms are far too general (I get over 1000
D> hits with: perl scope variable hash my symref - bad signal to noise
D> ratio).

try symrefs or symbolic references or soft references

use the words *I* mentioned.

I did. 'symref' was one of the terms. :)
and you fell into the trap of the evil symref. do not go there if you
value your coding career. there lies deamons you don't want to release.

and here is my standard rant on this:
[rant...] ... so why would you
use a specialized hash tree for this when a regular hash would work just
as well? and a regular hash has many advantages....

Uri's right; my solution is not great; it obscures (but does not
avoid) the trap he discusses. But I believe he's asking, "why are you
bothering to use an array (@) when you could use a hash (%) instead?"

I agree that hashes offer many advantages, but I'm not free to use a
hash in this case. I'm constructing a series of parameters to pass to
a module (HTML::Template's TMPL_LOOP), which expects an array (@)
reference. I want my code to be portable, so I don't want to hack on
HTML::Template.

The script is running under mod_perl, so it's especially important
that I lexically scope my variables.

It does not seem possible to "properly" scope/use an array (@) in the
manner I'm attempting. bummer! Time to rewrite some code...
 
U

Uri Guttman

DF> Uri wrote...
D> Hmmm. Either the question is not asked nearly as often as Uri recalls,
D> or else my Google search terms are far too general (I get over 1000
D> hits with: perl scope variable hash my symref - bad signal to noise
D> ratio).
DF> I did. 'symref' was one of the terms. :)

and i did say it was covered MANY times here. just pick a few threads
and read them.

DF> Uri's right; my solution is not great; it obscures (but does not
DF> avoid) the trap he discusses. But I believe he's asking, "why are
DF> you bothering to use an array (@) when you could use a hash (%)
DF> instead?"

huh?

DF> I agree that hashes offer many advantages, but I'm not free to use
DF> a hash in this case. I'm constructing a series of parameters to
DF> pass to a module (HTML::Template's TMPL_LOOP), which expects an
DF> array (@) reference. I want my code to be portable, so I don't
DF> want to hack on HTML::Template.

huh?

show some code to back up what you are saying. how is making the array a
lexical not portable? what portability issues do you see?

DF> The script is running under mod_perl, so it's especially important
DF> that I lexically scope my variables.

DF> It does not seem possible to "properly" scope/use an array (@) in the
DF> manner I'm attempting. bummer! Time to rewrite some code...

huh?

show some code. your words are not conveying much useful info.

uri
 
D

David Filmer

The fact that my last posting seems very clear to me but not to you is
troubling. Either I have it right but am expressing it poorly, or I
have it wrong. I believe I'm clearly expressing my understanding of
the subject, so I wonder if my understanding is all wrong. Please
allow me to briefly summarize my understanding, and prehaps you will
be kind enough to point out where I've gone astray.

The code is at the top of the post. You didn't like it. You were
right. I don't have any better code to post, because, as I understand
it, what I was trying to do cannot be done (and thus cannot be coded),
and I need to do something else.

What I was trying to do was use a variable-as-a-variablename, and my
original question was how I could properly scope it, because

my $foo = 'bar';
my @{$foo}; #ie, @bar

doesn't work. I thought it was a syntax problem.

What I believe you've said (and what I've concluded) is that it cannot
be done at all (at least not without unleashing the demons of hell).
It is flat-out impossible to scope a variable (with a 'my' statement)
if the variable is not a hard reference. Is my understanding of this
correct?

You suggested using a hash INSTEAD of an array, correct? But I can't
do that, because I'm trying to pass this object to a module
(HTML::Template) which expects an array, ie:

$template->param(THIS_LOOP => \@loop_data);

So I need to rewrite a section of my code to use a hard reference (ie,
@bar) instead of a symref (@{$foo} #where $foo eq 'bar'), and there's
no way around that (without unleashing the demons). Is this correct?
 
U

Uri Guttman

DF> The fact that my last posting seems very clear to me but not to you is
DF> troubling. Either I have it right but am expressing it poorly, or I
DF> have it wrong. I believe I'm clearly expressing my understanding of
DF> the subject, so I wonder if my understanding is all wrong. Please
DF> allow me to briefly summarize my understanding, and prehaps you will
DF> be kind enough to point out where I've gone astray.

DF> The code is at the top of the post. You didn't like it. You were
DF> right. I don't have any better code to post, because, as I understand
DF> it, what I was trying to do cannot be done (and thus cannot be coded),
DF> and I need to do something else.

symrefs CAN be done but they are nasty and evel and not needed for
general purpose data handling as you are doing.

DF> What I was trying to do was use a variable-as-a-variablename, and my
DF> original question was how I could properly scope it, because

DF> my $foo = 'bar';
DF> my @{$foo}; #ie, @bar

DF> doesn't work. I thought it was a syntax problem.

use strict rightly disallows that.

DF> What I believe you've said (and what I've concluded) is that it cannot
DF> be done at all (at least not without unleashing the demons of hell).
DF> It is flat-out impossible to scope a variable (with a 'my' statement)
DF> if the variable is not a hard reference. Is my understanding of this
DF> correct?

well, your wording is not perfect. my variables are not in the symbol
table so you can't get access to them via symrefs (even if they are allowed).

DF> You suggested using a hash INSTEAD of an array, correct? But I can't
DF> do that, because I'm trying to pass this object to a module
DF> (HTML::Template) which expects an array, ie:

i meant use a hash instead of a symref (which is really using the symbol
table as a hash).

DF> $template->param(THIS_LOOP => \@loop_data);

DF> So I need to rewrite a section of my code to use a hard reference
DF> (ie, @bar) instead of a symref (@{$foo} #where $foo eq 'bar'), and
DF> there's no way around that (without unleashing the demons). Is
DF> this correct?

i don't understand the problem. the param wants an array ref. the ref
could come from any array variable or be an anon array with []. this has
nothing to so with symrefs or hashes. you don't seem to understand perl
hard references. read perlreftut and perlref.

uri
 
B

Ben Morrow

Quoth (e-mail address removed) (David Filmer):
The fact that my last posting seems very clear to me but not to you is
troubling. Either I have it right but am expressing it poorly, or I
have it wrong. I believe I'm clearly expressing my understanding of
the subject, so I wonder if my understanding is all wrong.

Others have explained most of where you're wrong. Basically:

1. Symrefs (using-a-variable-as-a-variable-name) only work with globals.
2. Symrefs don't work under use strict.
3. This is for a good reason: they are dangerous, and not usually
necessary.
You suggested using a hash INSTEAD of an array, correct? But I can't
do that, because I'm trying to pass this object to a module
(HTML::Template) which expects an array, ie:

$template->param(THIS_LOOP => \@loop_data);

So I need to rewrite a section of my code to use a hard reference (ie,
@bar)

This is not a hard reference... this is just an array variable. A symref
is something like this:

our @foo; # must be global so we can use symrefs
my $bar = 'foo';
no strict 'refs'; # to allow symrefs
my @baz = @{$bar}; # @baz is now a copy of @foo

A hard ('proper') reference is something like this:

my @foo; # can take hard refs to lexical vars
my $bar = \@foo; # a ref, rather than just the name
my @baz = @{$bar}; # @baz is now a copy of @foo, again
instead of a symref (@{$foo} #where $foo eq 'bar'), and there's
no way around that (without unleashing the demons). Is this correct?

I don't think so... I presume you are trying to do something like this:

sub pass_this_param_to_template {
# $param should be the name of an array
my $param = shift;
$template->param(THIS_LOOP => \@{$param});
}

my @foo = qw/.../;
my @bar = qw/.../;
pass_this_param_to_template 'foo';

, where the array to pass in is not known until runtime? Uri's
suggestion to use a hash is correct (it is almost always the correct
answer if you thought the answer was symrefs). You want to read perllol,
perlreftut and perldsc, and code something like this:

sub pass_this_param_to_template {
# $param should be an arrayref
my $param = shift;
$template->param(THIS_LOOP => $param);
}

my %params = (
foo => [qw/.../],
bar => [qw/.../],
);
pass_this_param_to_template $params{foo};

Here the members of the hash are references to (anon) arrays, so you can
pass them straight into $template->param. Note that I haven't used a
hash *instead of* an array, I have used a hash *of* (references to)
arrays.

Ben
 
M

Malcolm Dew-Jones

David Filmer ([email protected]) wrote:
: The fact that my last posting seems very clear to me but not to you is
: troubling. Either I have it right but am expressing it poorly, or I
: have it wrong. I believe I'm clearly expressing my understanding of
: the subject, so I wonder if my understanding is all wrong. Please
: allow me to briefly summarize my understanding, and prehaps you will
: be kind enough to point out where I've gone astray.

: >> show some code. your words are not conveying much useful info.

: The code is at the top of the post. You didn't like it. You were
: right. I don't have any better code to post, because, as I understand
: it, what I was trying to do cannot be done (and thus cannot be coded),
: and I need to do something else.

: What I was trying to do was use a variable-as-a-variablename, and my
: original question was how I could properly scope it, because

: my $foo = 'bar';
: my @{$foo}; #ie, @bar

: doesn't work. I thought it was a syntax problem.

: What I believe you've said (and what I've concluded) is that it cannot
: be done at all (at least not without unleashing the demons of hell).
: It is flat-out impossible to scope a variable (with a 'my' statement)
: if the variable is not a hard reference. Is my understanding of this
: correct?

Yes. `my' allows the compiler, at compile time, to define a variable.
Defining a variable at compile time means various things, including doing
such things as allocating memory and assigning a name to that memory
address. When your code is running then various things have to happen,
including such things as accessing that location in memory.

If you want perl to be able to use a `my' variable then you have to give
perl all the information it needs about the variable at compile time.
That includes the name, because that is how perl knows which address in
memory holds the data that implements that variable.

If you don't want to give all the data about the variable to the compiler
at compile time (i.e. its name) then there are two things that can be
done (I doubt that either is what you need to do!)

One possibility is to use a global variable. Perl doesn't need to know
the name at compile time because it looks up the name when the program is
running. To do that, all perl has to know is where in memory the
information about names is stored, and it can calculate that at compile
time because that is simply one of the many internal data structures
created by the compiler itself.

This is very powerful, but is rarely the best way to solve a problem.


A second possibility is to generate the code when the program runs. That
way the name gets inserted into the code because the code is simply a
string, and perl doesn't compile it until you know the name. This is even
more powerful, but again, is rarely the best way to solve a problem.

E.g.

$variable_name = 'loop_data';
$my_program_segment =
" my \@$variable_name = (\"some value\");
do_something_with(\@$variable_name);
";
eval $my_program_segment;
die "$my_program_segment\n$@: $!" if $@;


I doubt that either of these are what you really need. I suspect there is
some thing about programming perl that you are misunderstanding.
Choosing which array to pass into a function should not be this difficult.


: You suggested using a hash INSTEAD of an array, correct? But I can't
: do that, because I'm trying to pass this object to a module
: (HTML::Template) which expects an array, ie:

: $template->param(THIS_LOOP => \@loop_data);

that could be written as

my $ref_to_the_correct_array =

#
# this is where I would put something to tell me which
# array I wish to use. I would show you the code but I
# don't understand what you want well enough to be able to
# do that.
#

# now use the array we just chose (sp?)

$template->param(THIS_LOOP => $ref_to_the_correct_array);
 
K

Kevin Collins

Quoth (e-mail address removed) (David Filmer):

Others have explained most of where you're wrong. Basically:

1. Symrefs (using-a-variable-as-a-variable-name) only work with globals.

Please clarify that, because I don't believe it :)

sub foo
{
my @bar = qw(a b c); # create array bar
my $baz = 'bar'; #
my @bee = @{$baz} # @bee == @bar
}

Every thing there is lexical and scoped to the subroutine, i.e., not global...
Or maybe I'm really confused?
2. Symrefs don't work under use strict.
3. This is for a good reason: they are dangerous, and not usually
necessary.

-snip-

Thanks,

Kevin
 
U

Uri Guttman

KC> Please clarify that, because I don't believe it :)

KC> sub foo
KC> {
KC> my @bar = qw(a b c); # create array bar
KC> my $baz = 'bar'; #
KC> my @bee = @{$baz} # @bee == @bar
KC> }

have you actually tested that code? why do you believe that last
assignment worked?

#!/usr/local/bin/perl

#use strict ;

print foo(), "\n" ;

sub foo {
my @bar = qw(a b c); # create array bar
my $baz = 'bar'; #
my @bee = @{$baz} # @bee == @bar
}

that printed a blank line as i would expect.

when i enabled strict, it bombed with this:

Can't use string ("bar") as an ARRAY ref while "strict refs" in use at
/home/uri/perl/test/symref_lex.pl line 10.

which is also as expected.

so please believe that symrefs don't work with lexical/my vars. my vars
are NOT in the symbol table so you can't access them via symrefs.
lexicals only work with real/hard refs (but hard refs can also work with
globals).

uri
 
K

Kevin Collins

KC> Please clarify that, because I don't believe it :)

KC> sub foo
KC> {
KC> my @bar = qw(a b c); # create array bar
KC> my $baz = 'bar'; #
KC> my @bee = @{$baz} # @bee == @bar
KC> }

have you actually tested that code? why do you believe that last
assignment worked?

No, I didn't - obviously I should have :)
#!/usr/local/bin/perl

#use strict ;

print foo(), "\n" ;

sub foo {
my @bar = qw(a b c); # create array bar
my $baz = 'bar'; #
my @bee = @{$baz} # @bee == @bar
}

that printed a blank line as i would expect.

when i enabled strict, it bombed with this:

Can't use string ("bar") as an ARRAY ref while "strict refs" in use at
/home/uri/perl/test/symref_lex.pl line 10.

which is also as expected.

so please believe that symrefs don't work with lexical/my vars. my vars
are NOT in the symbol table so you can't access them via symrefs.
lexicals only work with real/hard refs (but hard refs can also work with
globals).

I have now run the code and seen for myself. Its good to learn these things - I
guess I've never had a case where I attempted to do this before, and it seemed
that it should work.

Thanks for the explanation - your last paragraph makes it clear why this
doesn't work.

Kevin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top