1
votes

How can I use a Perl function to return a boolean value and a string?

For example, I am using regular expression to find something in a string. If found, return true and assign value to $msg, otherwise return false and assign another value to $msg.

Now I want to return both $result (boolean) and $msg (String) by "return ($result, $msg); ", and it's verified working. I am wondering if it is good to do it like this or is there a better way? I don't want to make other people confused when they are looking at my code.

use constant { true => 1, false => 0 };
my $output = "hello world";
my $msg;
my $result;

sub is_string_found
{
    if ($output =~ /hello/;)
    {
        $msg = "string is found";
        $result = true;
    }
    else
    {
        $msg = "string is not found";
        $result = false;
    }

    return ($result, $msg);
}
2
if there's a one to one correspondence of message and result, then it might be better to only return the boolean value, and deal with the message elsewhere -- an auxiliary function, if it's used a lot. - muhmuhten
that said, true and false don't really exist in perl as such. - muhmuhten
I probably wouldn't have the function that finds the string be the entity that decides what is displayed if it's found or not. Usually, you'd have it just return the true/false (or 1/0 or whatever) and have the caller upstream that deals with the user decide what's displayed for a string. - lurker
thanks for your comments. but sometimes upstream cannot get enough info to deal with different scenarios, for example, in the code above,if "hello" is NOT found, then set $msg = "hello is not found", else if "world" is not found, then set $msg = "world is not found", and for both cases, return false. If this function only return true/false, then upstream cannot get what's the reason of true/false. Do you mean i need a getter/setter function to pass the $msg to upstream functions in this case? - user1672190

2 Answers

3
votes

There are a few issues with your code, aside from using constants true and false:

  • You declare $msg and $result outside of your function. It would be better to reduce the visibility of these variables just to the function. Actually, you don't even need them.

  • You pass an argument to your sub by a variable in an outer scope, and return values in the same way. Use subroutine arguments and return values instead.

  • You have an erraneous ; in your if-condition.

Your sub can be shortened to

sub is_string_found {
  my ($str) = @_;
  return 1, "string is found" if $str =~ /hello/;
  return 0, "string is not found";
}

It can then be used like

my ($ok, $message) = is_string_found("hello world");

This is the best, and most obvious solution (to a Perl programmer).


You could also use an out-argument, so that you only return the success value:

sub is_string_found ($\$) {
  my ($str, $out_ref) = @_;
  if ($str =~ /hello/) {
    $$out_ref = "string is found";
    return 1;
  } else {
    $$out_ref = "string is not found";
    return;
  }
}

return without values returns undef in scalar context, the empty list in list context. It can then be invoked like

my $ok = is_string_found "hello world", my $message;

or

my $message;
is_string_found "hello world", $message
  or log_warning $message;

Note: you have to declare the sub before you first use it, either by defining it before usage, or putting the statement sub is_string_found ($\$); near the top of the script.

You don't have to use prototypes (and can instead use the aliasing behaviour of @_), but I'm not particulary fond of that solution

2
votes

What you are doing in terms of returning a list is fine. But using a hash may arguable be better:

sub is_string_found {
    my %h; 
    if ($output =~ /hello/)
    {   
        %h = (msg=>"string is found", retval=>1);
    }
    else
    {   
        %h = (msg=>"string is not found", retval=>0);
    }
    return %h; 
}

%d = is_string_found();
print $d{msg}, "\n" if not $d{retval};