Global symbol "%formsequence" requires explicit package name at line 37 - perl

I am trying to execute a Perl CGI script, but I am getting an error:
Global symbol "%formsequence" requires explicit package name at line 37.
I did some research and found that use strict forces me to declare the variables before I use them or store any data, but in my program I have declared them and that is why I don't understand the error. Here is my script:
#!/usr/bin/perl -w
use strict;
my %errors;
my %form;
my #formsequence;
my %fields = (
"lname" => "Last Name",
"phone" => "Phone",
"fname" => "Fist Name"
);
my %patterns = (
"lname" => '[A-Z][a-z]{2,50}',
"phone" => '\d{3}-\d{3}-\d{4}',
"fname" => '[A-Z][A-Za-z]{2,60}'
);
#formsequence = ("lname", "phone", "phone");
print "content-type/html\n\n";
if ($ENV{REQUEST_METHOD} eq "POST") {
&readformdata;
if (&checkrequiredfields) {
print "Form Data validated successfully!";
}
else {
foreach (keys (%fields)) {
if ($fields{$_} != $formsequence{$_}) { <-- line 37
$errors{$_}="Not in correct sequence\n";
}
}
}

I suspect you may be viewing the concept of an 'array' from the perspective of a PHP developer. In Perl a hash and an array are separate data structures.
Arrays are declared using the # prefix and you refer to elements using square brackets around an integer index:
my #names = ('Tom', 'Dick', 'Larry');
say $names[0]; # 'Tom'
say $names[-1]; # 'Larry'
my $count = #names; # $count now equals 3
foreach my $i (0..$#names) {
say $names[$i];
}
Hashes are declared using the % prefix and you refer to elements using curly braces around a string key:
my %rgb = (
red => '#ff0000',
white => '#ffffff',
blue => '#0000ff',
);
say $rgb{'red'}; # '#ff0000'
say $rgb{blue}; # '#0000ff' quotes optional around bareword keys
foreach my $k (keys %rgb) {
say $rgb{$k};
}
You wouldn't normally use the keys function on an array - in fact older versions of Perl don't even support it, newer versions will return a range of integers (e.g.: 0..2).
When you call keys on a hash the keys have no inherent order, and the order may change.
Other things worth knowing:
Using & to call a function is really old style (i.e. early 90s), these days we'd use readformdata() instead of &readformdata.
The != operator is a numeric comparison operator so only use it when the values you're comparing are actually numbers. If you want to check two strings are 'not equal' then use ne instead (e.g.: if($thing1 ne $thing2) { ... }).

This seems to be some rather old Perl.
You use -won the shebang line rather than use warnings (which has been available since Perl 5.6.0 was released in 2000.
You use a (presumably) custom readformdata() function instead of CGI,pm's params() method. CGI.pm was added to the Perl core in 1997 (it was recently removed - but that's not a reason to not use it).
You use ampersands on function calls. These haven't been necessary since Perl 5 was released in 1994.
Your problem is caused by declaring an array, #formsequence, which you then try to access as a hash - $formsequence{$_} means, "look up the key $_ in the hash %formsequence. In Perl, arrays and hashes are two completely different data types and it is possible (although not recommended for, hopefully, obvious reasons) to have an array and a hash with the same name.
You declare arrays like this - using #:
my #array = ('foo', 'bar', 'baz');
And access individual element like this - using [...]:
print $array[0]; # prints 'foo'
You declare hashes like this - using `%':
my %hash = (foo => 'Foo', bar => 'Bar', baz => 'Baz');
And access individual elements like ths - using {...}:
print $hash{foo}; # prints 'Foo'
Arrays are indexed using integers and are ordered. Hashes are indexed using strings and are unordered.
I can't really suggest a fix for your code as it's not really clear what you are trying to do. It appears that you want to check that parameters appear in a certain order, but this is doomed to failure as a) you can't guarantee the order in which CGI parameters are transmitted from the browser to your web server and b) you can't guarantee the order in which keys(%fields) will return the keys from your %fields hash.
If you explain in a little more detail what you are trying to do, then we might be able to help you more.

Related

Need help understanding portion of script (globs and references)

I was reviewing this question, esp the response from Mr Eric Strom, and had a question regarding a portion of the more "magical" element within. Please review the linked question for the context as I'm only trying to understand the inner portion of this block:
for (qw($SCALAR #ARRAY %HASH)) {
my ($sigil, $type) = /(.)(.+)/;
if (my $ref = *$glob{$type}) {
$vars{$sigil.$name} = /\$/ ? $$ref : $ref
}
}
So, it loops over three words, breaking each into two vars, $sigil and $type. The if {} block is what I am not understanding. I suspect the portion inside the ( .. ) is getting a symbolic reference to the content within $glob{$type}... there must be some "magic" (some esoteric element of the underlying mechanism that I don't yet understand) relied upon there to determine the type of the "pointed-to" data?
The next line is also partly baffling. Appears to me that we are assigning to the vars hash, but what is the rhs doing? We did not assign to $_ in the last operation ($ref was assigned), so what is being compared to in the /\$/ block? My guess is that, if we are dealing with a scalar (though I fail to discern how we are), we deref the $ref var and store it directly in the hash, otherwise, we store the reference.
So, just looking for a little tale of what is going on in these three lines. Many thanks!
You have hit upon one of the most arcane parts of the Perl language, and I can best explain by referring you to Symbol Tables and Typeglobs from brian d foy's excellent Mastering Perl. Note also that there are further references to the relevant sections of Perl's own documentation at the bottom of the page, the most relevant of which is Typeglobs and Filehandles in perldata.
Essentially, the way perl symbol tables work is that every package has a "stash" -- a "symbol table hash" -- whose name is the same as the package but with a pair of trailing semicolons. So the stash for the default package main is called %main::. If you run this simple program
perl -E"say for keys %main::"
you will see all the familiar built-in identifiers.
The values for the stash elements are references to typeglobs, which again are hashes but have keys that correspond to the different data types, SCALAR, ARRAY, HASH, CODE etc. and values that are references to the data item with that type and identifier.
Suppose you define a scalar variable $xx, or more fully, $main:xx
our $xx = 99;
Now the stash for the main package is %main::, and the typeglob for all data items with the identifier xx is referenced by $main::{xx} so, because the sigil for typeglobs is a star * in the same way that scalar identifiers have a dollar $, we can dereference this as *{$main::{xx}}. To get the reference to the scalar variable that has the identifier xx, this typeglob can be indexed with the SCALAR string, giving *{$main::{xx}}{SCALAR}. Once more, this is a reference to the variable we're after, so to collect its value it needs dereferencing once again, and if you write
say ${*{$main::{xx}}{SCALAR}};
then you will see 99.
That may look a little complex when written in a single statement, but it is fairly stratighforward when split up. The code in your question has the variable $glob set to a reference to a typeglob, which corresponds to this with respect to $main::xx
my $type = 'SCALAR';
my $glob = $main::{xx};
my $ref = *$glob{$type};
now if we say $ref we get SCALAR(0x1d12d94) or similar, which is a reference to $main::xx as before, and printing $$ref will show 99 as expected.
The subsequent assignment to #vars is straightforward Perl, and I don't think you should have any problem understanding that once you get the principle that a packages symbol table is a stash of typglobs, or really just a hash of hashes.
The elements of the iteration are strings. Since we don't have a lexical variable at the top of the loop, the element variable is $_. And it retains that value throughout the loop. Only one of those strings has a literal dollar sign, so we're telling the difference between '$SCALAR' and the other cases.
So what it is doing is getting 3 slots out of a package-level typeglob (sometimes shortened, with a little ambiguity to "glob"). *g{SCALAR}, *g{ARRAY} and *g{HASH}. The glob stores a hash and an array as a reference, so we simply store the reference into the hash. But, the glob stores a scalar as a reference to a scalar, and so needs to be dereferenced, to be stored as just a scalar.
So if you had a glob *a and in your package you had:
our $a = 'boo';
our #a = ( 1, 2, 3 );
our %a = ( One => 1, Two => 2 );
The resulting hash would be:
{ '$a' => 'boo'
, '%a' => { One => 1, Two => 2 }
, '#a' => [ 1, 2, 3 ]
};
Meanwhile the glob can be thought to look like this:
a =>
{ SCALAR => \'boo'
, ARRAY => [ 1, 2, 3 ]
, HASH => { One => 1, Two => 2 }
, CODE => undef
, IO => undef
, GLOB => undef
};
So to specifically answer your question.
if (my $ref = *$glob{$type}) {
$vars{$sigil.$name} = /\$/ ? $$ref : $ref
}
If a slot is not used it is undef. Thus $ref is assigned either a reference or undef, which evaluates to true as a reference and false as undef. So if we have a reference, then store the value of that glob slot into the hash, taking the reference stored in the hash, if it is a "container type" but taking the value if it is a scalar. And it is stored with the key $sigil . $name in the %vars hash.

Does Perl have an associative array type that can have any type of keys?

It seems that Perl can only have strings as the keys of a hash. (Has this been changed in a certain version of Perl?) It is very limiting to only be able to use strings as the key. What if I wanted an object or an array to be the key? In Python it is easy to use an array, tuple, and other objects that can compare, as dict keys. Perl does have the ability to compare things like arrays for equality, so I don't see why they can't be used as mapping-type keys.
Isn't there a way to use any key type in Perl? Is there a module that provides this?
Contrary to what you said, Perl does NOT have the ability to compare things like arrays for equality as you claim. For starters, Perl has no definition for array equality. And if the definition requires comparing the contents of the array, then Perl doesn't have definitions of equality for most things that can be found in an array either.
The closest Perl has for a definition of equality arrays is their address. If that's what you want to use, then it's quite easy:
$key = ['a', 'b'];
$hash{$key} = [ $key, $val ]; # Prevents the key from being freed.
print $hash{$key}[1];
Otherwise, Perl leaves it up to you to implement what you want instead of forcing you to use what it provides. I see two main approaches.
A tied hash, basically code that presents the interface of a hash without actually being a hash table, can support any key type. You could use it to define your version of array equality. There might even be an existing module (although I didn't see one after a very quick search).
Another approach would be to create a function that produces a unique key from the key expression.
sub key{ "#_" } # Overly simplistic?
$hash{key('a', 'b')} = $val;
print $hash{key('a', 'b')};
AFAIK Perl simply stringifies the keys?
package Foo;
use Moose;
use overload ('""' => \&stringify);
sub stringify {
return "xxx";
}
package main;
use v5.10;
use Data::Dump 'pp';
my $foo = Foo->new;
my $hash = {$foo => 'bar'};
say pp($hash); // { xxx => "bar" }
This way you can also use whatever you want as a hash key. See also this thread on Perl Monks.
As for the equality, take a look at equality operators in perlop. The == operator compares numerically, the eq operator compares stringwise. This means that for example (4, 2) == (1, 2) is true (as scalar (4, 2) is 2), which might be a surprise for you.
Yes, there is module for this on CPAN: Tie::Hash::StructKeyed. It takes into account whole structure, but as a snapshot. each/keys will return original reference.
Yes it does, use fieldhashes (Hash::Util::FieldHash for 5.10+ and Hash::Util::FieldHash::Compat for before 5.10) to register your hashes as fieldhashes, and you can use any reference (and thus, any object) as a key for those hashes (it numifies the reference, essentially, and provides logic for dealing with CLONEing across threads and garbage collecting the keys), for example:
use Hash::Util qw/fieldhashes/;
fieldhashes \my (%foo, %bar, %baz);
my %data = (a => 1, b => 2, c => 3);
my $stuff = {t => 2, u => 3, l => 9};
$foo{\%data} = 'x';
$foo{$stuff} = 'a';
$bar{\%data} = 'y';
$bar{$stuff} = 'b';
$baz{\%data} = 'z';
$baz{$stuff} = 'c';
print "$foo{\%data} $bar{\%data} $baz{\%data}\n";
print "$foo{$stuff} $bar{$stuff} $baz{$stuff}\n";

Confusion about proper usage of dereference in Perl

I noticed the other day that - while altering values in a hash - that when you dereference a hash in Perl, you actually are making a copy of that hash. To confirm I wrote this quick little script:
#! perl
use warnings;
use strict;
my %h = ();
my $hRef = \%h;
my %h2 = %{$hRef};
my $h2Ref = \%h2;
if($hRef eq $h2Ref) {
print "\n\tThey're the same $hRef $h2Ref";
}
else {
print "\n\tThey're NOT the same $hRef $h2Ref";
}
print "\n\n";
The output:
They're NOT the same HASH(0x10ff6848) HASH(0x10fede18)
This leads me to realize that there could be spots in some of my scripts where they aren't behaving as expected. Why is it even like this in the first place? If you're passing or returning a hash, it would be more natural to assume that dereferencing the hash would allow me to alter the values of the hash being dereferenced. Instead I'm just making copies all over the place without any real need/reason to beyond making syntax a little more obvious.
I realize the fact that I hadn't even noticed this until now shows its probably not that big of a deal (in terms of the need to go fix in all of my scripts - but important going forward). I think its going to be pretty rare to see noticeable performance differences out of this, but that doesn't alter the fact that I'm still confused.
Is this by design in perl? Is there some explicit reason I don't know about for this; or is this just known and you - as the programmer - expected to know and write scripts accordingly?
The problem is that you are making a copy of the hash to work with in this line:
my %h2 = %{$hRef};
And that is understandable, since many posts here on SO use that idiom to make a local name for a hash, without explaining that it is actually making a copy.
In Perl, a hash is a plural value, just like an array. This means that in list context (such as you get when assigning to a hash) the aggregate is taken apart into a list of its contents. This list of pairs is then assembled into a new hash as shown.
What you want to do is work with the reference directly.
for (keys %$hRef) {...}
for (values %$href) {...}
my $x = $href->{some_key};
# or
my $x = $$href{some_key};
$$href{new_key} = 'new_value';
When working with a normal hash, you have the sigil which is either a % when talking about the entire hash, a $ when talking about a single element, and # when talking about a slice. Each of these sigils is then followed by an identifier.
%hash # whole hash
$hash{key} # element
#hash{qw(a b)} # slice
To work with a reference named $href simply replace the string hash in the above code with $href. In other words, $href is the complete name of the identifier:
%$href # whole hash
$$href{key} # element
#$href{qw(a b)} # slice
Each of these could be written in a more verbose form as:
%{$href}
${$href}{key}
#{$href}{qw(a b)}
Which is again a substitution of the string '$href' for 'hash' as the name of the identifier.
%{hash}
${hash}{key}
#{hash}{qw(a b)}
You can also use a dereferencing arrow when working with an element:
$hash->{key} # exactly the same as $$hash{key}
But I prefer the doubled sigil syntax since it is similar to the whole aggregate and slice syntax, as well as the normal non-reference syntax.
So to sum up, any time you write something like this:
my #array = #$array_ref;
my %hash = %$hash_ref;
You will be making a copy of the first level of each aggregate. When using the dereferencing syntax directly, you will be working on the actual values, and not a copy.
If you want a REAL local name for a hash, but want to work on the same hash, you can use the local keyword to create an alias.
sub some_sub {
my $hash_ref = shift;
our %hash; # declare a lexical name for the global %{__PACKAGE__::hash}
local *hash = \%$hash_ref;
# install the hash ref into the glob
# the `\%` bit ensures we have a hash ref
# use %hash here, all changes will be made to $hash_ref
} # local unwinds here, restoring the global to its previous value if any
That is the pure Perl way of aliasing. If you want to use a my variable to hold the alias, you can use the module Data::Alias
You are confusing the actions of dereferencing, which does not inherently create a copy, and using a hash in list context and assigning that list, which does. $hashref->{'a'} is a dereference, but most certainly does affect the original hash. This is true for $#$arrayref or values(%$hashref) also.
Without the assignment, just the list context %$hashref is a mixed beast; the resulting list contains copies of the hash keys but aliases to the actual hash values. You can see this in action:
$ perl -wle'$x={"a".."f"}; for (%$x) { $_=chr(ord($_)+10) }; print %$x'
epcnal
vs.
$ perl -wle'$x={"a".."f"}; %y=%$x; for (%y) { $_=chr(ord($_)+10) }; print %$x; print %y'
efcdab
epcnal
but %$hashref isn't acting any differently than %hash here.
No, dereferencing does not create a copy of the referent. It's my that creates a new variable.
$ perl -E'
my %h1; my $h1 = \%h1;
my %h2; my $h2 = \%h2;
say $h1;
say $h2;
say $h1 == $h2 ?1:0;
'
HASH(0x83b62e0)
HASH(0x83b6340)
0
$ perl -E'
my %h;
my $h1 = \%h;
my $h2 = \%h;
say $h1;
say $h2;
say $h1 == $h2 ?1:0;
'
HASH(0x9eae2d8)
HASH(0x9eae2d8)
1
No, $#{$someArrayHashRef} does not create a new array.
If perl did what you suggest, then variables would get aliased very easily, which would be far more confusing. As it is, you can alias variables with globbing, but you need to do so explicitly.

Perl: simple foreach on hash hands mixed results? [duplicate]

activePerl 5.8 based
#!C:\Perl\bin\perl.exe
use strict;
use warnings;
# declare a new hash
my %some_hash;
%some_hash = ("foo", 35, "bar", 12.4, 2.5, "hello",
"wilma", 1.72e30, "betty", "bye\n");
my #any_array;
#any_array = %some_hash;
print %some_hash;
print "\n";
print #any_array;
print "\n";
print $any_array[0];
print "\n";
print $any_array[1];
print "\n";
print $any_array[2];
print "\n";
print $any_array[3];
print "\n";
print $any_array[4];
print "\n";
print $any_array[5];
print "\n";
print $any_array[6];
print "\n";
print $any_array[7];
print "\n";
print $any_array[8];
print "\n";
print $any_array[9];
Output as this
D:\learning\perl>test.pl
bettybye
bar12.4wilma1.72e+030foo352.5hello
bettybye
bar12.4wilma1.72e+030foo352.5hello
betty
bye
bar
12.4
wilma
1.72e+030
foo
35
2.5
hello
D:\learning\perl>
What decided the elements print order in my sample code?
Any rule to follow when print a mixed(strings, numbers) hash in Perl? Thank you.
bar12.4wilma1.72e+030foo352.5hello
[Updated]
With you guys help, i updated the code as below.
#!C:\Perl\bin\perl.exe
use strict;
use warnings;
# declare a new hash
my %some_hash;
%some_hash = ("foo", 35, "bar", 12.4, 2.5, "hello",
"wilma", 1.72e30, "betty", "bye");
my #any_array;
#any_array = %some_hash;
print %some_hash;
print "\n";
print "\n";
print #any_array;
print "\n";
print "\n";
my #keys;
#keys = keys %some_hash;
for my $k (sort #keys)
{
print $k, $some_hash{$k};
}
output
D:\learning\perl>test.pl
bettybyebar12.4wilma1.72e+030foo352.5hello
bettybyebar12.4wilma1.72e+030foo352.5hello
2.5hellobar12.4bettybyefoo35wilma1.72e+030
D:\learning\perl>
Finially, after called keys and sort functions. The hash keys print followed the rule below
2.5hellobar12.4bettybyefoo35wilma1.72e+030
Elements of a hash are printed out in their internal order, which can not be relied upon and will change as elements are added and removed. If you need all of the elements of a hash in some sort of order, sort the keys, and use that list to index the hash.
If you are looking for a structure that holds its elements in order, either use an array, or use one of the ordered hash's on CPAN.
the only ordering you can rely upon from a list context hash expansion is that key => value pairs will be together.
From perldoc -f keys:
The keys of a hash are returned in an apparently random order. The actual random order is subject to change in future versions of Perl, but it is guaranteed to be the same order as either the values or each function produces (given that the hash has not been modified). Since Perl 5.8.1 the ordering is different even between different runs of Perl for security reasons (see Algorithmic Complexity Attacks in perlsec).
...
Perl has never guaranteed any ordering of the hash keys, and the ordering has already changed several times during the lifetime of Perl 5. Also, the ordering of hash keys has always been, and continues to be, affected by the insertion order.
Also note that while the order of the hash elements might be randomised, this "pseudoordering" should not be used for applications like shuffling a list randomly (use List::Util::shuffle() for that, see List::Util, a standard core module since Perl 5.8.0; or the CPAN module Algorithm::Numerical::Shuffle), or for generating permutations (use e.g. the CPAN modules Algorithm::Permute or Algorithm::FastPermute), or for any cryptographic applications.
Note: since you are evaluating a hash in list context, you are at least guaranteed that each key is followed by its corresponding value; e.g. you will never see an output of a 4 b 3 c 2 d 1.
I went over your code and made some notes that I think you will find helpful.
use strict;
use warnings;
# declare a new hash and initialize it at the same time
my %some_hash = (
foo => 35, # use the fat-comma or '=>' operator, it quotes the left side
bar => 12.4,
2.5 => "hello",
wilma => 1.72e30,
betty => "bye", # perl ignores trailing commas,
# the final comma makes adding items to the end of the list less bug prone.
);
my #any_array = %some_hash; # Hash is expanded into a list of key/value pairs.
print "$_ => $some_hash{$_}\n"
for keys %some_hash;
print "\n\n", # You can print multiple newlines in one string.
"#any_array\n\n"; # print takes a list of things to print.
# In print #foo; #foo is expanded into a list of items to print.
# There is no separator between the members of #foo in the output.
# However print "#foo"; interpolates #foo into a string.
# It inserts spaces between the members of the arrays.
# This is the block form of 'for'
for my $k (sort keys %some_hash)
{
# Interpolating the variables into a string makes it easier to read the output.
print "$k => $some_hash{$k}\n";
}
Hashes provide unordered, access to data by a string key.
Arrays provide access to ordered data. Random access is available by using a numerical index.
If you need to preserve the order of a group of values, use an array. If you need to look up members of the group by an associated name, use a hash.
If you need to do both, you can use both structures together:
# Keep an array of sorted hash keys.
my #sorted_items = qw( first second third fourth );
# Store the actual data in the hash.
my %item;
#item{ #sorted_items } = 1..4; # This is called a hash slice.
# It allows you to access a list of hash elements.
# This can be a very powerful way to work with hashes.
# random access
print "third => $item{third}\n";
# When you need to access the data in order, iterate over
# the array of sorted hash keys. Use the keys to access the
# data in the hash.
# ordered access
for my $name ( #sorted_items ) {
print "$name => $item{$name}\n";
}
Looking at your code samples, I see a couple of things you might want to work on.
how looping structures like for and while can be used to reduce repeated code.
how to use variable interpolation
BTW, I am glad to see you working on basics and improving your code quality. This investment of time will pay off. Keep up the good work.
The elements are (almost certainly) printed out in the order they appear (internally) in the hash table itself -- i.e. based on the hash values of their keys.
The general rule to follow is to use something other than a hash table if you care much about the order.
Hashes are not (necessarily) retrieved in a sorted manner. If you want them sorted, you have to do it yourself:
use strict;
use warnings;
my %hash = ("a" => 1, "b" => 2, "c" => 3, "d" => 4);
for my $i (sort keys %hash) {
print "$i -> $hash{$i}\n";
}
You retrieve all the keys from a hash by using keys and you then sort them using sort. Yeah, I know, that crazy Larry Wall guy, who would've ever thought of calling them that? :-)
This outputs:
a -> 1
b -> 2
c -> 3
d -> 4
For most practical purposes, the order in which a hash table (not just Perl hash variables, but hash tables in general) can be considered random.
In reality, depending on the hashing implementation, the order may actually be deterministic. (i.e., If you run the program multiple times putting the same items into the hash table in the same order each time, they'll be stored in the same order each time.) I know that Perl hashes used to have this characteristic, but I'm not sure about current versions. In any case, hash key order is not a reliable source of randomness to use in cases where randomness is desirable.
Short version, then:
Don't use a hash if you care about the order (or lack of order). If you want a fixed order, it will be effectively random and if you want a random order, it will be effectively fixed.
A hash defines no ordering properties. The order in which things come out will be unpredictable.
And if you are crazy and have no duplicate values in your hash, and you need the values sorted, you can call reverse on it.
my %hash = ("a" => 1, "b" => 2, "c" => 3, "d" => 4);
my %reverse_hash = reverse %hash;
print $_ for sort keys %reverse_hash;
Caveat is the unique values part, duplicates will be overwritten and only one value will get in.

Dynamic array using perl code. Begineer [duplicate]

I want to create arrays dynamically based on the user input. For example, if the user gives input as 3 then three arrays should be created with the name #message1, #message2, and #message3.
How do I do it in Perl?
Don't. Instead, use an array of arrays:
my #message;
my $input = 3;
for my $index ( 0..$input-1 ) {
$message[$index][0] = "element 0";
$message[$index][1] = 42;
}
print "The second array has ", scalar( #{ $message[1] } ), " elements\n";
print "They are:\n";
for my $index ( 0..$#{ $message[1] } ) {
print "\t", $message[1][$index], "\n";
}
Some helpful rules are at http://perlmonks.org/?node=References+quick+reference
I have to ask why you want to do this, because it's not the right way to go. If you have three streams of input, each of which needs to be stored as a list, then store one list, which is a list of the lists (where the lists are stored as array references):
my #input = (
[ 'data', 'from', 'first', 'user' ],
[ qw(data from second user) ],
[ qw(etc etc etc) ],
);
If you have names associated with each user's data, you might want to use that
as a hash key, for indexing the data against:
my %input = (
senthil => [ 'data', 'from', 'first', 'user' ],
ether => [ qw(data from second user) ],
apu => [ qw(etc etc etc) ],
);
Please refer to the Perl Data Structures Cookbook (perldoc perldsc) for more
on selecting the right data structure for the situation, and how to define
them.
Creating new named arrays dynamically is almost never a good idea. Mark Dominus, author of the enlightening book Higher-Order Perl, has written a three-part series detailing the pitfalls.
You have names in mind for these arrays, so put them in a hash:
sub create_arrays {
my($where,$n) = #_;
for (1 .. $n) {
$where->{"message$_"} = [];
}
}
For a quick example that shows the structure, the code below
my $n = #ARGV ? shift : 3;
my %hash;
create_arrays \%hash, $n;
use Data::Dumper;
$Data::Dumper::Indent = $Data::Dumper::Terse = 1;
print Dumper \%hash;
outputs
$ ./prog.pl
{
'message2' => [],
'message3' => [],
'message1' => []
}
Specifying a different number of arrays, we get
$ ./prog.pl 7
{
'message2' => [],
'message6' => [],
'message5' => [],
'message4' => [],
'message3' => [],
'message1' => [],
'message7' => []
}
The order of the keys looks funny because they're inside a hash, an unordered data structure.
Recall that [] creates a reference to a new anonymous array, so, for example, to add values to message2, you'd write
push #{ $hash{"message2"} }, "Hello!";
To print it, you'd write
print $hash{"message2"}[0], "\n";
Maybe instead you want to know how long all the arrays are:
foreach my $i (1 .. $n) {
print "message$i: ", scalar #{ $hash{"message$i"} }, "\n";
}
For more details on how to use references in Perl, see the following documentation:
Mark's very short tutorial about references, or perldoc perlreftut
Perl references and nested data structures, or perldoc perlref
Perl Data Structures Cookbook, or perldoc perldsc
In compiled languages, variables don't have a name. The name you see in the code is a unique identifier associated with some numerical offset. In an identifier like message_2 the '2' only serves to make it a unique identifier. Anybody can tell that you could make your three variables: message_125, message_216, and message_343. As long as you can tell what you should put into what, they work just as well as message_1...
The "name" of the variable is only for you keeping them straight while you're writing the code.
Dynamic languages add capability by not purging the symbol table(s). But a symbol table is simply an association of a name with a value. Because Perl offers you lists and hashes so cheaply, there is no need to use the programming/logistical method of keeping track of variables to allow a flexible runtime access.
Chances are that if you see yourself naming lists #message1, #message2, ... -- where the items differ only by their reference order, that these names are just as good: $message[1], $message[2], ....
In addition, since symbol tables are usually mapping from name-to-offset (either on the stack or in the heap), it's really not a whole lot more than a key-value pair you find in a hash. So hashes work just as good for looking up more distinct names.
$h{messages} = [];
$h{replies} = [];
I mean really if you wanted to, you could store everything that you put into a lexical variable into a single hash for the scope, if you didn't mind writing: $h{variable_name} for everything. But you wouldn't get the benefit of Perl's implicit scope management, and across languages, programmers have preferred implicit scope management.
Perl allows symbolic manipulation, but over the years the dynamic languages have found that a mixed blessing. But in Perl you have both "perspectives", to give them a name. Because you can determine what code in a compiled language is likely to do better than a dynamic language, it has been determined more error free to use a "compiled perspective" for more things: So as you can see with the availability of offset-management and lookup compiled behavior given to you in core Perl, there is no reason to mess with the symbol table, if you don't have to.
Creating an array dynamically, is as simple as: []. Assigning it to a spot in memory, when we don't know how many we want to store, is as easy as:
push #message, [];
And creating a list of lists all at once is as easy as:
#message = map { [] } 1..$num_lists;
for some specified value in $num_lists.