I defined hash and array constants, When passing those to a function, I'll have to pass them as references. However I'm wondering what the correct syntax is.
Consider this example:
#!/usr/bin/perl
use strict;
use warnings;
use constant AC => qw(a b c);
sub f($)
{
print "ref=", ref $_[0], "\n";
print "$_\n" foreach (@{$_[0]});
}
f(\AC);
When I run it I get:
ref=SCALAR
Use of uninitialized value $_ in concatenation (.) or string at /run/media/whatever/constref.pl line 10.
The Perl debugger prints AC
as an array:
13: f(\AC);
DB<1> x AC
0 'a'
1 'b'
2 'c'
DB<2> c
The List Constants section in the constant pragma docs tells us that
Constants may be lists of more (or less) than one value.
...
List constants are lists, not arrays.
This means, among other properties, that one cannot take a reference of that "list constant" as if it were a single entity, like an array variable is; it behaves as a list, a group of scalars.†
In order to accomplish what is asked then we need to build an (anonymous) array reference out of that list and pass that, f([AC])
use warnings;
use strict;
use feature 'say';
use constant AC => qw(a b c);
sub f {
my ($r) = @_;
say "ref=", ref $r;
say for @$r;
}
f( [ AC ] );
This passes the "list constant" as a single value, an array reference, and it prints as expected. However, I don't like having to copy values, nor to further lose any semblance of constant-ness.‡ There are other ways to do this but those are even less palatable to me.§
I'd suggest to reconsider the tool to use when proper read-only variables are needed.
There are other libraries for this and I'd recommend Const::Fast, or Readonly.
use Const::Fast;
const my @const_ary => qw(a b c);
f( \@const_ary ); # same f() from above
use Readonly;
Readonly my @carr => qw(a b c);
f( \@carr ); # same f() from above
These are lexical variables that one can handle like any other. See docs.
† Attempting to formally "take a reference" of a list results in a list of references
\($v, $t) --> \$v, \$t
‡ While the AC
itself is a constant, the list that it is associated with isn't read-only
use constant AC => qw(a b c);
(AC)[1] = "other";
say for AC;
prints
a
other
c
They're just not constant.
§ I can see two other ways
The constant pragma produces (is implemented as) a subroutine. Then one could use that and pass it as such, f(\&AC)
, and then use it as such, say for $r->()
.
However, now we have to pass and dereference a subroutine off of that list symbol (AC
), and get a list. This is a really bad hack.
The code in the question uses a "constant list." One can use a reference instead and that can be passed as such
use constant AC => [ qw(a b c) ];
# same sub f { } as above
f( AC ); # prints as expected
However, I don't see how to dereference AC
to get the whole list (@{ AC }
doesn't go?), apart from copying it to an arrayref first, like in f()
. But then that defies the purpose of having it as a constant
-- and all pretense to constant-ness is dropped.