Making sure that we're dealing with an array (reference)

T

Tore Aursand

Hi!

One thing that happens quite often when I program in Perl, is that I need
to initialise a variable to be an array reference.

Let me explain what I'm talking about:

sub init {
my %ARGS = @_;

my $paths = $ARGS{'paths'} || [];
}

In the code above, I want $self->{'_paths'} to always be an array
reference, even if $ARGS{'paths'} is just a plain string. How can I do
this the best way?

Currently, I'm stuck with code like this:

my $paths = $ARGS{'paths'} || [];
$paths = ( ref($paths) eq 'ARRAY' ) ? $paths : [ $paths ];

It seems to work, though, but I feel that there's something wrong with
this approach...?

Even though I have a lot og scripts and modules which uses this code, I
have luckily gathered the code above in my Misc module (50K and still
growing). The function is called 'as_arrayref' and is quite nice;

my $ref = as_arrayref( $something );

Tata! :)
 
B

Brian McCauley

Tore Aursand said:
One thing that happens quite often when I program in Perl, is that I need
to initialise a variable to be an array reference.
$paths = ( ref($paths) eq 'ARRAY' ) ? $paths : [ $paths ];

It seems to work, though, but I feel that there's something wrong with
this approach...?

I can't fault it except...

If you know $paths can never be an reference to anything but an array
(and often you do know this) it simplifies to:

$paths = ref($paths) ? $paths : [ $paths ];

Conversly if $paths is a reference to an object that can function as
an array (either because it really is a blessed array or because it
overloads @{}) then (ref($paths) eq 'ARRAY') will be false even though
it perhaps you would not want to wrap the array.

I can't really see any way round this as it is impossible to tell if
the array-ness of a blessed array is part of the public interface.

It's also seems OTT to test overload::Method($path,'@{}').
Even though I have a lot og scripts and modules which uses this code, I
have luckily gathered the code above in my Misc module (50K and still
growing). The function is called 'as_arrayref' and is quite nice;

my $ref = as_arrayref( $something );

Seems a resonable thing to do.

That said having a huge 'Misc' module may not be as good as several
smaller ones.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
U

Uri Guttman

TA> Currently, I'm stuck with code like this:

TA> my $paths = $ARGS{'paths'} || [];
TA> $paths = ( ref($paths) eq 'ARRAY' ) ? $paths : [ $paths ];

TA> It seems to work, though, but I feel that there's something wrong with
TA> this approach...?

i do the same thing in many places. nothing i know to simplify it.

uri
 
B

Ben Morrow

Quoth Tore Aursand said:
sub init {
my %ARGS = @_;

my $paths = $ARGS{'paths'} || [];
}

In the code above, I want $self->{'_paths'} to always be an array
reference, even if $ARGS{'paths'} is just a plain string. How can I do
this the best way?

Currently, I'm stuck with code like this:

my $paths = $ARGS{'paths'} || [];
$paths = ( ref($paths) eq 'ARRAY' ) ? $paths : [ $paths ];

It seems to work, though, but I feel that there's something wrong with
this approach...?

You could always do

my $paths = $ARGS{paths} ? [ $ARGS{paths} ] : [];

or one of

my $paths = [ grep defined, $ARGS{paths} ];
my $paths = [ grep $_, $ARGS{paths} ];

Obviously this generalises:

my $paths = [ (grep defined, $ARGS{paths}, $ENV{MY_ENV})[0] ];

Ben
 
T

Tore Aursand

One thing that happens quite often when I program in Perl, is that I need
to initialise a variable to be an array reference.

$paths = ( ref($paths) eq 'ARRAY' ) ? $paths : [ $paths ];

It seems to work, though, but I feel that there's something wrong with
this approach...?

If you know $paths can never be an reference to anything but an array
(and often you do know this) it simplifies to:

$paths = ref($paths) ? $paths : [ $paths ];

That's correct. I also have in mind that I don't pass complex structures
(or blessed objects) to this function. My current test scenario is like
this:

my @array = qw( a b c );
my $ref1 = as_arrayref( @array ); # [ 'a', 'b', 'c' ]
my $ref2 = as_arrayref( \@array ); # [ 'a', 'b', 'c' ]
my $ref3 = as_arrayref( 'a b c' ); # [ 'a b c' ]

Thus, it seems to work as expected;

sub as_arrayref {
my @data = @_;
if ( @data > 1 ) {
return \@data;
}
else {
return ( ref($data[0]) eq 'ARRAY' ) ? $data[0] : [ $data[0] ];
}
}

It sure doesn't account for everything, especially when dealing with
complex structures, but that isn't necessary in my case. Anyone have a
better way?

If not - on towards 'as_hashref'. :)
 
R

Rocco Caputo

Currently, I'm stuck with code like this:

my $paths = $ARGS{'paths'} || [];
$paths = ( ref($paths) eq 'ARRAY' ) ? $paths : [ $paths ];

It seems to work, though, but I feel that there's something wrong with
this approach...?

If you usually expect $ARGS{paths} to be an array reference, then most
of the time your code will be the equivalent of $paths = $paths. That
sort of inefficiency displeases me. I'd throw out the C-style ?:
operator and instead go with something more Perly. Like this:

my $paths = $ARGS{'paths'} || [];
$paths = [ $paths ] unless ref($paths) eq 'ARRAY';

-- Rocco Caputo - http://poe.perl.org/
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top