
Perl has a special kind of block called a do-block (the ‘do’ keyword followed by a block). This kind of block can be used as a term in an expression, or it can take a statement modifier.
When used as a term, the result returned is the value of the last statement evaluated in the block (rather like a subroutine’s default return value):
my $in = do{print "Enter a number:";<STDIN>};
print $in;
The context of the return value is the context of the expression (in the above case, since we assigned to a scalar, scalar context). The above isn’t a terribly useful example — but what about when you want to localize a global for a limited scope? Consider reading in an entire file into a scalar (inside of a larger script where you don’t want to change $/ for the duration of the script):
my $file = 'data';
open(FILE, $file) || die "Can't open $file: $!";
my $contents;
{
local $/; # $/ is locally undefined
$contents = <FILE>;
}
print $contents;
A simpler method using a do-block might be:
my $file = 'data';
open(FILE, $file) || die "Can't open $file: $!";
my $contents = do{local $/;<FILE>};
print $contents;
With a statement modifier, this kind of block allows for a ‘run at least once’ form of the while statement:
my $rand = int(rand(10)) + 1;
my $guess;
do{
print "Enter your guess: ";
$guess = <STDIN>;
} while $guess != $rand;
print "Yes: the number is $guess";
This allows us to use what looks like an uninitialized value in the conditional — it works only because the condition is tested after each block (by which time the $guess variable has a value).
The do block is also convenient for switch or case like statement blocks:
my $rand = int(rand(10)) + 1;
{
print "Enter your guess: ";
chomp(my $guess = <STDIN>);
$guess < $rand && do{print "Too low\n"; redo};
$guess > $rand && do{print "Too high\n";redo};
}
print "You guessed it!\n";
These case like examples could easily be solved using other means (like standard if/else statements), this is just another example of TMTOWTDI (there’s more than one way to do it).
*****