chiborg
chiborg

Reputation: 28084

How to check if several variables are empty in Perl

I have a Perl script where variables must be initialized before the script can proceed. A lengthy if statement where I check each variable is the obvious choice. But maybe there is a more elegant or concise way to check several variables.

Edit: I don't need to check for "defined", they are always defined with an empty string, I need to check that all are non-empty.

Example:

my ($a, $b, $c) = ("", "", "");

# If-clauses for setting the variables here

if( !$a || !$b || !$c) {
  print "Init failed\n";
}

Upvotes: 4

Views: 16244

Answers (5)

Sinan Ünür
Sinan Ünür

Reputation: 118128

I am assuming that empty means the empty string, not just any false value. That is, if 0 or "0" are ever valid values post-initialization, the currently accepted answer will give you the wrong result:

use strict; use warnings;

my ($x, $y, $z) = ('0') x 3;
# my ($x, $y, $z) = ('') x 3;

for my $var ($x, $y, $z) {
    die "Not properly initialized\n" unless defined($var) and length $var;
}

Now, this is pretty useless as a validation, because, more than likely, you would like to know which variable was not properly initialized if this situation occurs.

You would be better served by keeping your configuration parameters in a hash so you can easily check which ones were properly initialized.

use strict; use warnings;

my %params = (
    x => 0,
    y => '',
    z => undef,
);

while ( my ($k, $v) = each %params ) {
    validate_nonempty($v)
        or die "'$k' was not properly initialized\n";
}

sub validate_nonempty {
    my ($v) = @_;
    defined($v) and length $v;
}

Or, if you want to list all that were not properly initialized:

my @invalid = grep is_not_initialized($params{$_}), keys %params;
die "Not properly initialized: @invalid\n" if @invalid;

sub is_not_initialized {
    my ($v) = @_;
    not ( defined($v) and length $v );
}

Upvotes: 8

David W.
David W.

Reputation: 107040

Your way is readable and easy to understand which means it's easy to maintain. Restating your boolean using de Morgan's laws:

if (not($a and $b and $c)) {
   warn(qq(Not all variables are initialized!))
}

That way, you're not prefixing not in front of every variable, and it doesn't affect readability. You can use List::Util or List::MoreUtils, but they don't really add to the legibility.

As Sinan Ünür stated, if you put the variables in a hash, you could parse through the hash and then list which variables weren't initialized. This might be best if there are a lot of these variables, and the list keeps changing.

foreach my $variable qw(a b c d e f g h i j) {
    if (not $param{$variable}) {
        warn qq(You didn't define $variable\n);
    }
}

You can use Getopts::Long to put your parameter values inside a hash instead of separate variables. Plus, the latest versions of Getopts::Long can now operate on any array and not just @ARGV.

Upvotes: 3

DVK
DVK

Reputation: 129403

What do you mean by "initialized"? Have values that are not "undef"?

For a small amount of values, the straightforward if check is IMHO the most readable/maintainable.

if (!$var1 || !$var2 || !$var3) {
    print "ERROR: Some are not defined!"; 
}

By the way, checking !$var is a possible bug in that "0" is false in Perl and thus a string initialized to "0" would fail this check. It's a lot better to use $var eq ""

Or better yet, space things out for >3 values

if    (!$var1          # Use this if your values are guarantee not to be "0"
    || $var2 eq ""     # This is a LOT better since !$var fails on "0" value
    || $var3 eq "") {

    print "ERROR: Some are not defined!"; 
}

If there are so many values to check that the above becomes hard to read (though with per-line check as in the second example, it doesn't really ever happen), or if the values are stored in an array, you can use grep to abstract away the checking:

# We use "length" check instead of "$_ eq ''" as per tchrist's comment below
if (grep { length } ($var1, $var2, $var3, $var4, $var5, @more_args) ) {
    print "ERROR: Some are not defined!"; 
}

If you must know WHICH of the values are not defined, you can use for loop (left as an obvious excercise for the reader), or a map trick:

my $i = -1; # we will be pre-incrementing
if (my @undefined_indexes = map { $i++; $_ ? () : $i }
                                ($var1, $var2, $var3, $var4, $var5, @more_args) ) {

    print "ERROR: Value # $_ not defined!\n" foreach @undefined_indexes; 
}

Upvotes: 8

Eugene Yarmash
Eugene Yarmash

Reputation: 149756

use List::Util 'first';

if (defined first { $_ ne "" } $a, $b, $c) {
    warn "empty";
}    

Upvotes: 7

zoul
zoul

Reputation: 104065

use List::MoreUtils 'all';
say 'Yes' if (all { defined } $var1, $var2, $var3);

Upvotes: 8

Related Questions