EricR
EricR

Reputation: 1497

perl function ignores undef arguments

I'm passing some arguments to a function, one of which might be undefined.

$a = ($config->function(param('a'),'int'));

my module contains a function which looks like this:

sub function{                    
        my $self = $_[0];           
        my $t = $_[1];              
        my $type = $_[2];           
        print "$self,$t,$type<br/>";
}

I've tried with shift instead of the @_ syntax, but there's no change. The problem is that if $config->function is called with an undefined param('a') it prints like this:

MY_FUNC=HASH(0x206e9e0),name, it seems that $t is being set to the value of what $type should be and the undef is being ignored completely.

Upvotes: 3

Views: 2134

Answers (3)

brian d foy
brian d foy

Reputation: 132811

[I started this as a comment but it got too long].

Inside an argument list, arguments are evaluated in list context. Two answers have already noted that, but I think you missed it for all of the other things they were talking about.

Beyond that, param has to handle at least three cases, and the interface Lincoln chose, although sometimes annoying, is a good enough way to handle them.

The query parameter a does not appear at all:

b=1

The query parameter a appears, but with no value:

a=&b=1

The query parameter a appears with a value:

a=1&b=1

Upvotes: 1

Borodin
Borodin

Reputation: 126722

The CGI param method is correctly returning an empty list in the case of an error. This is standard behaviour for Perl subroutines and methods, which return a false value in the case of an erorr.

As @mob says, an explicit return undef is wrong precisely because it returns a one-element list in list context. This is a true value and implies success, which would break a lot of code if it was changed

All you need to do is change your code to extract the parameter separately

my $param = param('a');
$config->function($param, 'int'));

or if you're really keen to put the call in the parameter list then you can write

$config->function(scalar param('a'), 'int'));

or

$config->function(param('a') // undef, 'int'));

Upvotes: 3

mob
mob

Reputation: 118605

undef is perfectly valid in a parameter list. I suspect that the problem here is that the param function is returning an empty list, rather than undef.

sub function {
    no warnings 'uninitialized';
    print join "/", @_;
}

function(undef,"foo");      #   outputs "/foo"
function((), "foo");        #   outputs "foo"

In the argument list to function, the param function is evaluated in list context.

sub param1 {
    return;     # undef in scalar context, but empty list in list context
}

sub param2 {
    return undef;    # scalar ctx: undef, list ctx: list with one undef elem
}

function(param1(), "foo");    #   param1() -> () ... outputs "foo"
function(param2(), "foo");    #   param2() -> (undef) ... outputs "/foo"

A workaround is to make sure that your param function is evaluated in scalar context.

function(scalar param1(), "foo");    # now outputs "/foo"

Note that actually saying return undef in your Perl subroutines is considered by some to be a code smell.

Upvotes: 4

Related Questions