[This is a mid-week bonus Item since it’s so short]
Prior to Perl 5.10, you had to be a bit careful checking a Perl variable before you set a default value. An uninitialized value and a defined but false value both acted the same in the logical ||
short-circuit operator. The Perl idiom to set a default value looks like this:
$value ||= 'some default';
That’s the binary-assignment equivalent of an expression where you type out the variable twice:
$value = $value || 'some default';
However, some of the false values might be perfectly valid and meaningful. If there are no rabbits in the hutch, you don’t want to replace that actual value, which just happens to be false, with the default:
my $rabbits = 0; $rabbits = $rabbits || 1; #not what you want
The undef
value, however, is actually the absence of value. It’s the absence of meaningful value. Replacing that with a default is reasonable:
my $rabbits; # undef $rabbits = $rabbits || 1; # maybe what you want
To get around this, you don’t use the short-circuit operator. Instead, you can use the conditional operator, typing out the variable name three times:
$value = defined $value ? $value : 'some default';
You’ll mostly likely use this when you’re processing the command-line options or subroutine arguments:
sub set_values { my( $arg1, $arg2 ) = @_; $arg1 = defined $arg1 ? $arg1 : 'some default'; $arg2 = defined $arg2 ? $arg2 : 'some default'; }
That’s a bit messy, so Perl 5.10 introduces the defined-or operator, //
. Instead of testing for truth, it tests for defined-ness. If its lefthand value is defined, even if it’s false (i.e. 0
, '0'
, or the empty string), that’s what it returns, short-circuiting the righthand side. This works just fine, not replacing the 0
value that’s in $rabbits
already:
use 5.010; my $rabbits = 0; $rabbits = $rabbits // 1; # probably what you want
You can now reduce this back to the binary-assignment idiom:
use 5.010; my $rabbits = 0; $rabbits //= 1;
Now your subroutine paramter defaults look a bit neater:
sub set_values { my( $arg1, $arg2 ) = @_; $arg1 //= 'some default'; $arg2 //= 'some default'; }
This isn’t one of the Perl 5.10 features that you have to explicitly enable (Item 2: Enable new Perl features when you need them). As long as you are using Perl 5.10 or later it’s already available to you. However, you should still specify the Perl version (Item 83. Limit your distributions to the right platforms.).
You mention that
As long as you’re not using
//
, wouldn’t you write that rather?
Yes, you could also use a postfix conditional.
Iosif, what would happen if
$value
was defined? The conditional brian displays handles setting the value either way; you would have to write an assignment first and then your check for definedness, resulting in more code and slightly less understandable at first sight.In Iosif’s example, the variable keeps the value if already had if it is defined. In the example he quotes, I assigned the same value back to the same variable. At the end both do the same thing, but I was making a larger point. Even in his streamlined example, he has to type the variable name twice.