in reply to A cleaner way of scoping variables

There is a way you can avoid declaring $bar once and assining it an other time:

use strict; my $foo = 1; { my $bar = do { if ($foo) { "true"; } }; print $bar; }

You still need a pair of braces around the whole construct. If you want $bar to be local, you need a block, how else would perl know where the variable is local.

The block is not ugly imo. I often use blocks in perl just to declare local variables. There is a way to avoid such blocks, but that involves changing programming style: you have to write short (50 lines most) subroutines that do one thing and do it well, and you can declare local variables at the top of each subroutine, with one my() statement perl sub (and preferable at most 7 variables). This is a good programming style in C imo (see Documentation/CodingStyle in the linux source), but doesn't always worth in Perl.

This is a bit OT, but note that I write the curlies of a block inline if the block contains only one line of code.

Replies are listed 'Best First'.
Re^2: A cleaner way of scoping variables
by Aristotle (Chancellor) on Aug 09, 2004 at 13:44 UTC

    This code has a problem: if the condition is false, the condition is the last expression evaluated in the do block, so whatever the condition evaluates to becomes the result of the do block.

    $ perl -le'print do { "x" if 1 }' x $ perl -le'print do { "x" if 0 }' 0

    In your case, the value of $foo is assigned to $bar if $foo is false. This could be particularly nasty because you'll never notice if you don't run tests with $foo being 0 or the empty string rather than undefined.

    You must make sure that your do blocks always evaluate to an intended result. In this case, you have to add an else { undef } clause.

    Makeshifts last the longest.

      You must make sure that your do blocks always evaluate to an intended result. In this case, you have to add an else { undef } clause.

      Indeed.

      In your case, the value of $foo is assigned to $bar if $foo is false.

      Perl is a bit wierd about the return value of a loop of which the body never runs. This code:

      #!/usr/bin/perl -w my $true = "foo"; my $false = "0"; my $dc = "bar"; warn do { $dc if $false }; warn do { $dc unless $true }; warn do { $dc while $false }; warn do { $dc until $true }; warn do { if ($false) { $dc } }; warn do { unless ($true) { $dc } }; warn do { while ($false) { $dc } }; warn do { until ($true) { $dc } }; warn do { $dc if "0" }; warn do { $dc unless "foo" }; warn do { $dc while "0" }; warn do { $dc until "foo" }; warn do { if ("0") { $dc } }; warn do { unless ("foo") { $dc } }; warn do { while ("0") { $dc } }; warn do { until ("foo") { $dc } }; __END__
      prints:
      Useless use of private variable in void context at a line 9. Useless use of private variable in void context at a line 10. Useless use of private variable in void context at a line 13. Useless use of private variable in void context at a line 14. Useless use of private variable in void context at a line 21. Useless use of private variable in void context at a line 22. 0 at a line 7. foo at a line 8. 0 at a line 9. foo at a line 10. 0 at a line 11. foo at a line 12. 0 at a line 13. foo at a line 14. 0 at a line 15. foo at a line 16. 0 at a line 17. Warning: something's wrong at a line 18. 0 at a line 19. Warning: something's wrong at a line 20. Warning: something's wrong at a line 21. Warning: something's wrong at a line 22.

        As often, Deparse comes to the rescue. With formatting adjusted for comparability with yours, the output is

        #!/usr/bin/perl -w my $true = "foo"; my $false = "0"; my $dc = "bar"; warn do { $dc if $false }; warn do { $dc unless $true }; warn do { $dc while $false }; warn do { $dc until $true }; warn do { if ($false) { $dc; } }; warn do { unless ($true) { $dc; } }; warn do { while ($false) { $dc; } }; warn do { until ($true) { $dc; } }; warn do { '0' }; warn do { 'foo' }; warn do { do { '0' } }; warn do { do { !1 } }; warn do { '0' }; warn do { !1 }; warn do { }; warn do { };

        Note the !1 — ie "not true", ie "The Real False", which is an empty string in Perl5. That explains your something's wrong messages: the loops are getting folded away at compile time, but apparently the compiler doesn't evaluate hard enough.

        Makeshifts last the longest.