user466663 user466663 - 24 days ago 6
Perl Question

Use of defined/undef in Perl

I am planning to pass two variables to a perl function, one of which may be optional. I am trying to check if the second one is defined or not, but it doesn't work correctly. When I called the function as myFunction(18), it assumes that the variable $optional is defined and goes to the else statement. But in the else statement when the $optional variable is being accessed it throws an "uninitialized" error. This is exactly opposite of what I have expected. Any help is greatly appreciated.

sub myFunction {
my ($length, $optional) = (@_);
if(undef($optional)
{
more code..
}
else
{
more code...
}
}

myFunction(18)

Answer

The correct function is defined. undef undefines $optional. What you want to do is something like this:

sub myFunction {
    my( $length, $optional ) = @_;
    if( ! defined $optional ) {
        # Do whatever needs to be done if $optional isn't defined.
    }
    else {
        # Do whatever can be done if $optional *is* defined.
    }
}

Another way to deal with it (especially Perl 5.10+) is to use the "defined or" operator, //, like this:

sub MyFunc {
    my $length = shift;
    my $optional = shift // 'Default Value';
    # Do your stuff here.
}

What that does is detect whether the return value of shift @_ is defined. Since you already called shift once, we're now testing the second parameter. If it's defined, assign the value to $optional. If it's not defined, assign 'Default Value' to $optional. Of course you have to come up with your own sane default.

If you're stuck in the dark ages of pre-Perl 5.10, you could accomplish the same with:

my $optional = shift;
$optional = defined $optional ? $optional : 'Default value';

...or...

my $length = shift;
my $optional = defined( $_[0] ) ? shift : 'Default value';

Either way, I often prefer having a sane default, rather than a totally separate control flow path. It's often a good way to simplify code.