Chris B.
Chris B.

Reputation: 49

perl using function return value as if statement condition

Is it possible in Perl to use a function's return value as the expression in an "if" statement? For example; in C I can write

if (!myFunction()){
   printf("myFunction returned false.\n");
} else {
   printf("myFunction returned true\n");
}

But in perl I find I must go through the pain of ..

$ret = myFunction();
if (!$ret){
    print "myFunction returned false.\n";
}

I know as soon as I post this someone will redirect me to several other posts of this question. But, obviously, I could not find what I'm looking for or I would not write this! So spare me the "have you tried searching for ...." messages!

Here is what myFunction() looks like.

sub myFunction
{
    my ($run, $runTime) = @_;
    my ($code);

    eval {
        $SIG{ALRM} = sub {die "Operation Timed Out";};

        alarm($run_time);
        $EXIT_STR = `$run`; # Execute $run and save output in EXIT_STR
        $code = $?;         # Save cmd exit code.
        $EXIT_CODE = $code; # Set a global value (EXIT_CODE)
        alarm(0);
        return($code);
    };
    if ($@) {
        if ($@ =~ /Operation Timed Out/) { 
            print "Time out\n";
            return(10);
        }
    }
}

After everyone's feedback I went back to the books to learn more about eval. After a bit of reading it was clearer that "eval" "returned" a value to the function it was part of. It was then up to me to decide what to do with the eval results. With that in mind I made some changes and the function works as I had hoped. Thanks to all!

Upvotes: 2

Views: 10630

Answers (4)

Miller
Miller

Reputation: 35208

You're attempting to call return for your subroutine from inside an eval. This will not perform as you expect as explained in the docs for return:

  • return EXPR
  • return

    Returns from a subroutine, eval, or do FILE with the value given in EXPR. ...

The bug you're facing can be demonstrated in the following example:

sub myFunction {
    eval {
        return "inside eval";
    };

    return "outside eval";
}

print myFunction();

Outputs:

outside eval

To fix your subroutine, assign your return value inside the eval, but actually return it from outside. Also, be sure to localize your alarm signal handler.

sub myFunction {
    my ($run, $runTime) = @_;

    my $code;

    eval {
        local $SIG{ALRM} = sub {die "Operation Timed Out";};
        alarm($run_time);
        $EXIT_STR = `$run`; # Execute $run and save output in EXIT_STR
        alarm(0);
        $code = $?;         # Save cmd exit code.
    };

    if ($@) {
        if ($@ =~ /Operation Timed Out/) { 
            print "Time out\n";
            $code = 10;
        }
    }

    return $code;
}

Upvotes: 0

drmrgd
drmrgd

Reputation: 733

You may need to explicitly return a false value in cases where you don't want the function to return True. Remember that perl functions will return the last evaluated statement in the absence of a real return value. So, take this example:

#!/usr/bin/perl

use warnings;
use strict;

my $x = 4;                                                                                                                            
my $y = 1;                                                                                                                            


if ( ! myFunction($x,$y) ) {
    print "myFunction returned false\n";
} else {
    print "myFunction returned true\n";
}

sub myFunction {
    my ($x,$y) = @_;
    my $response;

    if ( $x + $y == 2 ) {
        $response = "fun";
    } else {
        $response = "no fun";
    }
}

This will always print 'myFunction returned true' since either branch of the conditional is technically a true response. However, if you add a return value to the negative branch of the conditional, it will now work:

#!/usr/bin/perl

use warnings;
use strict;

my $x = 4;
my $y = 1;


if ( ! myFunction($x,$y) ) {
    print "myFunction returned false\n";
} else {
    print "myFunction returned true\n";
}

sub myFunction {
    my ($x,$y) = @_;
    my $response;

    if ( $x + $y == 2 ) {
        $response = "fun";
        return 1; # technically not really needed
    } else {
        $response = "no fun";
        return 0;
    }
}

$ perl test_funct.pl
myFunction returned false

Upvotes: 0

David W.
David W.

Reputation: 107060

Yup.

Wait. I can't give such a short answer...

Yes. If a function is inside an if statement, Perl will take the return value of the function as a boolean value. If the return value is zero, a blank string, a null value, a null string, or an undef, the if statement will be considered false. Otherwise, the if statement will be considered true.

Here's an easy to understand example:

if ( not is_odd( $number ) ) {
    print "$number is divisible by two\n";
}

sub is_odd {
    my $number = shift;
    return $number % 2;   # Modulo arithmetic
}

In the above $number % 2 will return zero on even numbers and one on odd numbers.

It's a good question. The best thing to do is to write a small script to try it out. Play around with it a bit:

For example. Let's add a second function we can use:

sub is_even {
    my $number = shift;
    return not is_odd( $number );
}

What does this return? How does this work in an if statement?

Upvotes: 1

Jim Garrison
Jim Garrison

Reputation: 86774

This will work fine.

The only caveat is that using it in an if-statement will provide scalar context to the return value so if something non-scalar is returned, it will get scalarized before the if condition is evaluated.

Upvotes: 0

Related Questions