I'm trying to port a library from Javascript to Perl, but having some issues detecting array arguments.
A stripped-down example (in Javascript) looks something like this:
const say = console.log;
function test(array, integer)
{
if(Array.isArray(array))
{
say("First argument is array");
}
else
{
say("First argument is not array");
array = [array];
}
for(let index = 0; index < array.length; ++index)
{
say(array[index]);
}
say("Second argument: ", integer);
say("");
}
var a = ["foo", "bar"];
var t = "baz";
var i = 1024;
say("Testing on array");
test(a, i);
say("Testing on string");
test(t, i);
Output:
Testing on array
First argument is array
foo
bar
Second argument: 1024
Testing on string
First argument is not array
baz
Second argument: 1024
And here's the Perl version:
use feature qw(say);
sub test
{
my ($text, $integer ) = @_;
my (@array) = @_;
if(ref(@array) == "ARRAY")
{
say("First argument is array");
}
else
{
say("First argument is not array");
@array = ($text);
}
for my $index (0 .. $#array)
{
say($array[$index]);
}
say("Second argument: ", $integer);
}
my @a = ("foo", "bar");
my $t = "baz";
my $i = 1024;
say("Testing on array");
test(@a, $i);
say("Testing on string");
test($t, $i);
Output:
Testing on array
First argument is array
foo
bar
1024
Second argument: bar
Testing on string
First argument is array
baz
1024
Second argument: 1024
I've also tried numerous other ways, such as prepending the backslash to the array name and so forth, but to no avail. I'm fairly certain that this must be possible in Perl. Or perhaps this is some sort of limitation of the language itself?
Perl subroutines do not take arrays as arguments, only scalars. Arrays in the sub call are collapsed into a list of scalars. You have 2 options if you want to pass an array.
test(\@a, $i)
, or test([ @a ], $i)
. Or better yet, pass the scalar arguments first, then take the rest of the arguments into an array.I suggest solution 1. Typically you can then do something like
test($i, @a);
sub test {
my $i = shift;
my @a = @_;
....
}
Or
test($i, [ @a ]);
sub test {
my $i = shift;
my $aref = shift;
my @a = @$aref; # expand to normal array (not strictly needed)
....
}
Note that passing the reference to the array @a
will allow the sub to alter the values in the array, so passing it as an anonymous array [ @a ]
is safer.
Also, the code:
my @a;
print ref(\@a);
Will print ARRAY
, but ref(@a)
will print nothing.
Also, if you had used
use strict;
use warnings;
You would have gotten the very enlightening warning
Argument "ARRAY" isn't numeric in numeric eq (==)
Which tells you that in string comparison, you should use eq
and not ==
which is numerical. Because Perl will silently cast the empty string to 0
in numerical context, and it will cast the string ARRAY
to 0
, the result of the comparison is true, which leads your comparison to return a false positive.
Never write Perl code without strict
and warnings
.
Thank you, great answer!
@SirGalahad You're welcome