thanos1983 has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I know this title sounds like a very common issue, but I came here to seek your wisdom on my observation. I have a script that processes some values and then stores them into an array.

While I was trying to observe if the array contains element(s) I found several tutorials and documentation online that should work, such as exists, defined, How do I test if an array is empty or not? etc.

I created a small demonstration script to replicate my curiosity question.

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @a = (); my @b = ( undef ); print "\@a is not Empty\n" if (@a); print "\@b is not Empty\n" if (@b); print "\@a is not Empty grep\n" if grep { defined($_) } @a; print "\@b is not Empty grep\n" if grep { defined($_) } @b; print Dumper \@a; print Dumper \@b;

Sample of output:

@b is not Empty $VAR1 = []; $VAR1 = [ undef ];

Now that I am thinking about it more, still undef it occupies a position on the array. Possibly this is the reason that if (@b) still prints the text.

From my point of view in cases that a script can contain undef values someone should use the if grep { defined($_) } @b functionality to determine if the array is empty, alternatively a simple if condition should do the work.

Can someone provide a bit of more information regarding undef. Thank you in advance for your time and effort.

Seeking for Perl wisdom...on the process of learning...not there...yet!

Replies are listed 'Best First'.
Re: How to determine if an array contains an undef value?
by BrowserUk (Patriarch) on Jan 04, 2015 at 16:36 UTC

    An array containing an undef is not empty; it contains the undef. In that case @array in a scalar context (eg. if( @array ); returns the number of elements, which is 1, therefore true.

    It may be an undefined value, but it is still a value.

    So, based upon what you've said, your problem becomes not: Is the array empty?; but rather: Does the array contain any defined values?

    Whilst that can be determined with grep, and may be perfectly adequate if your arrays are known to be small; if there is any chance that you could be dealing with large arrays that might contain lots of undefs, then you might also consider using one of the any() implementations (eg. List::Util::any() ) which will short circuit when it sees the first defined value:

    print "\@b is not Empty any\n" if any { defined() } @b;

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      It makes more sense now. Thank you for your time and effort reading and replying to my question.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: How to determine if an array contains an undef value?
by Laurent_R (Canon) on Jan 04, 2015 at 16:40 UTC
    Hi,

    your @b array is not empty, it has one element which happens to be undef. If you run something like:

    print scalar @b;
    it will print 1, which is why, if you evaluate the array in boolean context (... if (@b);) you get a true value and your sentence is printed.

    If you want to check if the array contains at least one defined element, yes, you probably have to do ... if grep { defined($_) } @b; or something similar. You may want something else, though, if your array is large.

    Update: corrected a typo.

      Hello Laurent_R ,

      Thank you for your time and effort reading and replying to my question. Initially I thought that undef means empty but now it makes more sense undef can be a possition reserved but currently undefined.

      Again thank you for your time and effort.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: How to determine if an array contains an undef value?
by Anonymous Monk on Jan 04, 2015 at 16:45 UTC

    By the way, in addition to the answers already given, a common pitfall:

    sub foo { return } sub bar { return undef } my $a = foo(); # $x is undef, if($x) is false my @b = foo(); # @b is empty, if(@b) is false my $c = bar(); # $c is undef, if($c) is false my @d = bar(); # @d is (undef), if(@d) is true!!

    because a return with no arguments is context-sensitive.

      Oops, obviously s/\$x/\$a/g

      Hello Anonymous Monk,

      Thank you for your input, this is an interesting observation.

      Seeking for Perl wisdom...on the process of learning...not there...yet!

        That observation might be extended to say ... “be careful of simple-tests for ‘falseness,’ if there are several different kinds of ‘falseness’ that you actually need to distinguish.”   Explicitly test for things using exists(), defined(), and so on.   Actually, I customarily test explicitly for every explicit that I expect to see, and cause the program to die() if it falls through all of the cases.   Tests for the “falseness” of the return-value are used in my code only when the value is 1 or 0.   The program catches a lot of its own bugs this way ... especially a concern in a typeless language like Perl.