home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam    

Book HomeLearning Perl, 3rd EditionSearch this book

4.4. Return Values

The subroutine is always invoked as part of an expression, even if the result of the expression isn't being used. When we invoked &marine earlier, we were calculating the value of the expression containing the invocation, but then throwing away the result.

Many times, we'll call a subroutine and actually do something with the result. This means that we'll be paying attention to the return value of the subroutine. All Perl subroutines have a return value -- there's no distinction between those that return values and those that don't. Not all Perl subroutines have a useful return value, however.

Since all Perl subroutines can be called in a way that needs a return value, it'd be a bit wasteful to have to declare special syntax to "return" a particular value for the majority of the cases. So Larry made it simple. Every subroutine is chugging along, calculating values as part of its series of actions. Whatever calculation is last performed in a subroutine is automatically also the return value.

For example, let's define this subroutine:

sub sum_of_fred_and_barney {
  print "Hey, you called the sum_of_fred_and_barney subroutine!\n";
  $fred + $barney;  # That's the return value
}

The last expression evaluated in the body of this subroutine is the sum of $fred and $barney, so the sum of $fred and $barney will be the return value. Here's that in action:

$fred = 3;
$barney = 4;
$c = &sum_of_fred_and_barney; # $c gets 7
print "\$c is $c.\n";
$d = 3 * &sum_of_fred_and_barney; # $d gets 21
print "\$d is $d.\n";

That code will produce this output:

Hey, you called the sum_of_fred_and_barney subroutine!
$c is 7.
Hey, you called the sum_of_fred_and_barney subroutine!
$d is 21.

That print statement is just a debugging aid, so that we can see that we called the subroutine. You'd take it out when the program is finished. But suppose you added another line to the end of the code, like this:

sub sum_of_fred_and_barney {
  print "Hey, you called the sum_of_fred_and_barney subroutine!\n";
  $fred + $barney;  # That's not really the return value!
  print "Hey, I'm returning a value now!\n"; # Oops!
}

In this example, the last expression evaluated is not the addition; it's the print statement. Its return value will normally be 1, meaning "printing was successful,"[104] but that's not the return value we actually wanted. So be careful when adding additional code to a subroutine to ensure that the last expression evaluated will be the desired return value.

[104]The return value of print is true for a successful operation and false for a failure. We'll see how to determine the kind of failure later in Chapter 11, "Filehandles and File Tests".

So, what happened to the sum of $fred and $barney in that subroutine? We didn't put it anywhere, so Perl discarded it. If you had requested warnings, Perl (noticing that there's nothing useful about adding two variables and discarding the result) would likely warn you about something like "a useless use of addition in a void context." The term void context is just a fancy of saying that the answer isn't being stored in a variable or used by another function.

"The last expression evaluated" really means the last expression evaluated, rather than the last line of text. For example, this subroutine returns the larger value of $fred or $barney:

sub larger_of_fred_or_barney {
  if ($fred > $barney) {
    $fred;
  } else {
    $barney;
  }
}

The last expression evaluated is the single $fred or $barney, which becomes the return value. We won't know whether the return value will be $fred or $barney until we see what those variables hold at runtime.

A subroutine can also return a list of values when evaluated in a list context.[105] Suppose you wanted to get a range of numbers (as from the range operator, ..), except that you want to be able to count down as well as up. The range operator only counts upwards, but that's easily fixed:

[105]You can detect whether a subroutine is being evaluated in a scalar or list context using the wantarray function, which lets you easily write subroutines with specific list or scalar context values.

sub list_from_fred_to_barney {
  if ($fred < $barney) {
    # Count upwards from $fred to $barney
    $fred..$barney;
  } else {
    # Count downwards from $fred to $barney
    reverse $barney..$fred;
  }
}
$fred = 11;
$barney = 6;
@c = &list_from_fred_to_barney; # @c gets (11, 10, 9, 8, 7, 6)

In this case, the range operator gives us the list from 6 to 11, then reverse reverses the list, so that it goes from $fred (11) to $barney (6), just as we wanted.

These are all rather trivial examples. It gets better when we can pass values that are different for each invocation into a subroutine instead of relying on global variables. In fact, that's coming right up.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.











??????????????@Mail.ru