BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:

Perl 5 has several places where it allows either a (possibly compound) statement, or a block. For example,

@array = grep $_ != 1, @array; @array = grep{ $_ != 1 } @array; @array = map ++$_, @array; @array = mapp{ ++$_ } @array; print for 1 .. 10; for( 1 .. 10 ) { print; } push @a, $_ while <FH>; while( <FH> ) { push @a, $_; }

Ignoring any performance difference that might come from avoiding an extra level of scope, is anyone aware of any piece of code that would run unchanged as a statement or a block, that would behave differently in one relative to the other?


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re: statement vs. block?
by lodin (Hermit) on Apr 12, 2008 at 01:45 UTC

    Something like this?

    our ($For, $While, $Map, $Grep, $If) = qw( For While Map Grep If) ; local $For = 'local' for 1; local $While = 'local' while ! $a++; map +(local $Map = 'local'), 1; grep +(local $Grep = 'local'), 1; local $If = 'local' if 1; print "For: $For\n"; print "While: $While\n"; print "Map: $Map\n"; print "Grep: $Grep\n"; print "If: $If\n"; __END__ For: For While: While Map: Map Grep: Grep If: local
    Here, all loop constructs introduces a scope for the expression just as they would if it was a block. if however doesn't.

    While speaking about blocks for map and grep (and sort):

    map { use strict; } LIST
    fails with '"use" not allowed in expression ...'. A do block can be used to "upgrade" the block though avoid the ambiguity (see ysth's reply:
    map do { use strict; }, LIST
    works. (Interestingly, this uses map EXPR, LIST ...)

    lodin

      map { use strict; } LIST
      fails with '"use" not allowed in expression ...'.
      I think this is just a funny case of guessing that "{ bareword" begins an expression, not a block, but it dies before even noticing the missing , after }.

      Disambiguating it as map {; use strict; } @ARGV works fine.

      Here, all loop constructs introduces a scope for the expression just as they would if it was a block. if however doesn't.

      What if?

      >perl -MO=Deparse -e"local $If = 'local' if 1;" local $If = 'local'; -e syntax OK

      However, fixing the test so if actually exists at run-time doesn't alter the results.

Re: statement vs. block?
by kyle (Abbot) on Apr 11, 2008 at 23:30 UTC

    If the block has a list in it, you can't use it as a "statement".

    use Data::Dumper; my @short = (0..2); my @x = map { ($_, $_) } @short; print Dumper \@x; my @y = map ($_, $_), @short; print Dumper \@y; __END__ $VAR1 = [ 0, 0, 1, 1, 2, 2 ]; $VAR1 = [ undef ];

    With warnings, this says "Useless use of private array in void context".

      That's because your map line is being parsed as map($_, $_) which is assigned to @y, followed by the array @short in void context (i.e. B::Deparse with the appropriate flags says ((my(@y) = map($_, $_)), @short);). If you disambiguate with a + (my @z = map +($_, $_), @short;) or explicitly parenthesize where map's arguments end (my @w = map( ($_, $_), @short );) it'll be parsed correctly ((my(@z) = map(($_, $_), @short));).

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

        Maybe I'm not getting what the OP is asking for. I read "any piece of code that would run unchanged as a statement or a block, that would behave differently in one relative to the other" as some stuff such that "map {stuff } @any" doesn't do the same thing as "mapstuff, @any" (but does run). I provided that.

Re: statement vs. block?
by jwkrahn (Abbot) on Apr 12, 2008 at 01:28 UTC
    print for my @x = 1 .. 10; for ( my @y = 1 .. 10 ) { print } print "@x\n@y\n";
Re: statement vs. block?
by parv (Parson) on Apr 12, 2008 at 02:05 UTC

    Don't you mean an expression instead of a statement?

Re: statement vs. block?
by ysth (Canon) on Apr 12, 2008 at 01:31 UTC
    Could you try asking again? After several rereadings, I still don't know what you are saying.

    There are places that require either a simple scalar or a block; other forms of statement wouldn't work there.

    And there's the ambiguity between hashref-{} and block-{}.

    Dunno if either of those are what you are looking for.

      No it's not syntactic ambiguites I'm looking for. lodin's got the gist and a couple of good examples below. I'm looking for cases where the contents of a block form, is legally acceptable with the expression form, but would behave differently in some way.

      It's mostly intellectual curiosity. I prefer the syntax of the block version of map and grep, but for really trivial expressions with high iteration counts, the introduction of a block can have a measurable, and even significant effect on performance.

      I got to wondering if it would be possible to recognise when a block was equivalent to an expression (statement) and have the compiler do away with the push/pop of scope.

      Then I got to thinking about whether there are other places where both block and expression forms exist and what would be the effect of this kind of optimisation on them. And then ... I asked the question :)


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.