Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Subroutine evaluated as boolean

by Anonymous Monk
on Oct 12, 2014 at 22:37 UTC ( [id://1103567]=perlquestion: print w/replies, xml ) Need Help??

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

I made a subroutine that returns a list of data in most circumstances, but sometimes returns an empty list (for "not found"). I want to do stuff if the return list is empty. I thought I could do this:
if(!searchsub($value)) { #stuff }

But, that is occasionally being evaluated as true for a nonempty list. (From my testing, this seems to be when the first list is found again. But that may be wrong.) The following is good:
my @arr=searchsub($value); if(!@arr) { #stuff }

Placing the return into an array first makes it work as I expect. How is the subroutine being evaluated, if not as a list? Also, is there a shortcut to avoid the extra array?

Replies are listed 'Best First'.
Re: Subroutine evaluated as boolean
by LanX (Saint) on Oct 12, 2014 at 22:51 UTC
    It depends on how you return that list.

    Because the returned expression is evaluated in the boolean (scalar) context.

    The way context is propagated into the sub is one of the peculiarities if Perl5.

    Could you show us the code of the return line?

    edit

    E.g. return $x,$y will be true if $y is true.

    But return @x will only be false if @x is empty.

    See also Context propagation into subs and evals

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

Re: Subroutine evaluated as boolean
by Anonymous Monk on Oct 13, 2014 at 00:30 UTC

    perldata:

    A scalar value is interpreted as FALSE in the Boolean sense if it is undefined, the null string or the number 0 (or its string equivalent, "0"), and TRUE if it is anything else. The Boolean context is just a special kind of scalar context where no conversion to a string or a number is ever performed.

    perlsyn:

    The number 0, the strings '0' and "" , the empty list (), and undef are all false in a boolean context. All other values are true. Negation of a true value by ! or not returns a special false value. When evaluated as a string it is treated as "" , but as a number, it is treated as 0. Most Perl operators that return true or false behave this way.

    LanX already said that return just propagates the context of the sub call. Lists evaluated in scalar context return their last value, which is different from arrays, which return their size. Compare:

    $ perl -wMstrict -le 'my $x = ("a","b","c"); print $x;' Useless use of a constant ("a") in void context at -e line 1. Useless use of a constant ("b") in void context at -e line 1. c $ perl -wMstrict -le 'my @y = ("a","b","c"); my $x = @y; print $x;' 3

    One way to do what you want might be via the wantarray function:

    return wantarray ? ($return,$values,$here) : $found_item_count;
Re: Subroutine evaluated as boolean
by boftx (Deacon) on Oct 13, 2014 at 01:08 UTC

    wantarray can be your friend, too.

    You must always remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.
Re: Subroutine evaluated as boolean
by Anonymous Monk on Oct 13, 2014 at 00:33 UTC
    Original poster here.
    This is my code (some names have been changed to protect the innocent).
    sub searchsub { my ($wanted)=@_; $wanted=extract_value($wanted); for(@$table) { return($_->{VALUE}, $_->{NAME}, $_->{ADDRESS}) if $_->{VALUE} eq + $wanted } () }

    So the problem is that it's evaluating ADDRESS instead of the list itself? This would make sense, since the address of the first list is usually 0.
    Thank you!
      if ($_->{VALUE} eq $wanted) { return wantarray ? ( $_->{VALUE}, $_->{NAME}, $_->{ADDRESS} ) : 1; }
      or
      if ($_->{VALUE} eq $wanted) { return wantarray ? @$_{qw( VALUE NAME ADDRESS )} : 1; }
      > So the problem is that it's evaluating ADDRESS instead of the list itself?

      Yes that's the effect if the scalar comma operator.

      Just copy the list to a temporary @array to be returned.

      Or return a literal construct like @{[L,I,S,T]}

      update

      Or best use a hash slice

       return @$_{VALUE,NAME,ADDRESS} if ...

      Cheers Rolf

      (addicted to the Perl Programming Language and ☆☆☆☆ :)

        In fact, return @$_{'VALUE','ADDRESS'} has the same problem as my original code. But return @{[@$_{'VALUE','ADDRESS'}]} works great, if it is a little confusing to a beginner like me.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1103567]
Front-paged by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2024-04-23 21:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found