Undefined Array in Perl

Is there some way to tell if an array in Perl is undefined or null? I find myself running into situations where I would like to distinguish between an empty array and one that has not yet been filled (or has not been filled for some reason).

So, for example, with a reference to an array, I can do this:

my $apples;
$apples = get_apples();
if(defined $apples){

if(scalar @$apples == 0){
# We successfully got the list of apples, but there were none
}

}else{

# There was a problem getting the list of apples

}

      

My only complaint about this is that "my apples" doesn't tell you that $ apples is meant to be an array reference, so @apples will be more specific.

It doesn't seem like there is a way to do something with the array explicitly, is that the case? Is another variable required to indicate if the array was successfully populated?

my @apples;
(@apples) = get_apples();

      

Couldn't check for successful return of apples, right? Or am I missing something?

Edit: I know that get_apples can both return success and a list to fill the array, but I'm curious if there is a way to specify null or undefined with just an array.

+3


source to share


6 answers


In Perl, there is no difference between an empty array and an uninitialized array.

$ perl -MDevel::Peek -e 'print Dump(\@a)'
SV = RV(0x20033b00) at 0x20033af0
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x20091830
  SV = PVAV(0x200350c0) at 0x20091830
    REFCNT = 2
    FLAGS = ()
    ARRAY = 0x0
    FILL = -1
    MAX = -1
    ARYLEN = 0x0
    FLAGS = (REAL)

$ perl -MDevel::Peek -e '@a=(); print Dump(\@a)'
SV = RV(0x20033b00) at 0x20033af0
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x20091818
  SV = PVAV(0x200350c0) at 0x20091818
    REFCNT = 2
    FLAGS = ()
    ARRAY = 0x0
    FILL = -1
    MAX = -1
    ARYLEN = 0x0
    FLAGS = (REAL)

      



Your only hope might be to check the attribute of the MAX

inner object AV

to see if the array is being used to store any data:

use B;
@b = ();
@c = (1..100); @c = ();
print B::svref_2object(\@b)->MAX;      # -1
print B::svref_2object(\@c)->MAX;      # 99

      

+7


source


  • Is there some way to tell if an array in Perl is undefined or null?

Not. Arrays can be empty or contain scalars.



There is a better way to do what you want: throw an exception. The separation of error codes and return values ​​has been bugaboo since the days of C. This makes this function difficult to use and leads to more bugs. Exceptions solve this problem and you don't need to skew your error checking code (or most likely forget).

sub get_apples {
    ...
    die "How do you like them apples?" if $it_didnt_work;
    return @apples;
}

# If get_apples() fails, the program throws an error.  Good, that
# should be the default behavior.
my @apples = get_apples();

# Or maybe you want to do something with the error.
my @apples = eval { get_apples() };
if( $@ ) {
    ...handle the error...
}

      

+6


source


The reason you can do my $apples;

is fill @$apples

in a routine get_apples()

and then do is if(@$apples==0)

because of the autovivification of scanners.

As mob points out, this doesn't work for arrays.

By the way, this could mean that it get_apples()

is passing a hash reference (or, if you want to be more Enterprisey, an object GetAppleReturn

), which in pseudocode looks like

{
  success=>1,# or 0 if it failed
  apples=>[$apple1,$apple2,...] #array reference of apples
}

      

So, you could do:

my @apples;
my $rv=get_apples();
if($rv->{success})
{
  if(scalar(@{$rv->{apples}})==0)
  {
    print "Success, but no apples.\n";
  }
  else
  {
    #do whatever
  }
}
else
{
  print "There was a problem getting the apples.  How do ya like them apples?\n";
}

      

0


source


How about using it ref()

?

my $apples;

print 'what type of object is $apples? ' . ref($apples) . $/;

$apples = get_apples();

print 'what type of object is $apples now? ' . ref($apples) . $/;

sub get_apples {
    my $empty_apple_array = [];
    return $empty_apple_array;
}

      

when $ apples is first created ref()

it returns nothing because it is not yet a reference to anything.

Then we make a reference to an empty array. Now ref()

knows that it is an array reference, even if it is empty.

0


source


You can return a singleton array containing undef to indicate an error, then do the following:

my @apples = get_apples();
if (@apples) {
    if (defined $apples[0]) {
        # you have apples
    } else {
        # some error occurred
    }
} else {
    # no apples
}

      

0


source


Even though Perl can tell the difference between an uninitialized array and an empty array (which it can't), it wouldn't help you determine if an error returned get_apples

, because you wouldn't have a way of my @apples = get_apples()

not doing the job when an error occurs.

You may be wrong about what the return @a

array is returning. Subs cannot return arrays. They can only return 0 or more scalars. return @a

returns a result @a

that is the contents of the array in the context of the list.

There is no way to distinguish null items returned due to an error from a successful response of null items through return values. (You can of course use an out-of-band channel like an exception or a global variable.)

Since subs can only return a list of scalars, you can only do two things:

  • Count the number of scalars returned.
  • Examine the returned scalars.

To achieve your goal, you need to find a case where one of them is distinguished by error and success.

When returning a ref array, it is checked whether the return value is defined or not.

You can do something like this if the first value returned (if any) will always be defined, but it's pretty ugly.

sub apples {
    if (...error...) {
       return undef;
    } else {
        return ...;
    }
}

my @apples = apples();
if (@apples && !defined($apples[0])) {
   ... an error occurred...
}

      

I recommend against this.

-1


source







All Articles