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

Why does this work
my %hash = map { $_ => "stuff_$_" } qw(asdf qwert zxcv);
But this
my %hash = map { "stuff_$_" => $_ } qw(asdf qwert zxcv);
results in a syntax error (syntax error ... near "} qw(asdf qwert zxcv)")

The only difference is the order of the values in the BLOCK.

perl 5.8.5

FOLLOW UP:
Since I don't particularly like any of the solutions to this problem that have been proposed (although most do work) I decided to follow the advice of a co-worker
Back in my day we used 'foreach' and we liked it!

It would seem to me that the more common case would be using map to generate key-values pairs for each iteration instead of an anonymous hash for each. So why not make the later have to use something extra... for instance:
my %hash = map { {"stuff_$_" => $_} } qw(asdf qwert zxcv);
would easily tell the parser it's an anon-hash. So anything with a '{' is a block until otherwise told it is not.

Replies are listed 'Best First'.
Re: order in map
by NetWallah (Canon) on May 02, 2005 at 19:45 UTC
    From perldoc perlfunc documentation of "map":

    { starts both hash references and blocks, so map { ... could be either the start of map BLOCK LIST or map EXPR, LIST. Because perl doesn't look ahead for the closing } it has to take a guess at which its dealing with based what it finds just after the {. Usually it gets it right, but if it doesn't it won't realize something is wrong until it gets to the } and encounters the missing (or unexpected) comma. The syntax error will be reported close to the } but you'll need to change something near the { such as using a unary + to give perl some help

    This will parse correctly, forcing BLOCK:

    my %hash = map {+ qq(stuff_$_) => $_ } qw(asdf qwert zxcv)

         "There are only two truly infinite things. The universe and stupidity, and I'm not too sure about the universe"- Albert Einstein

      my %hash = map { 'stuff_'.$_ => $_ } qw(asdf qwert zxcv);
      also works, and is easier for most people to read.

                      - Ant
                      - Some of my best work - (1 2 3)

Re: order in map
by ryantate (Friar) on May 02, 2005 at 20:36 UTC
    This is indeed ugly as are many of the fixes (though I do like suaveant's). I think in perl6 this can be disambiguated as

    my %hash = map { "stuff_$_" => $_ } <== qw(asdf qwert zxcv);

    ... as per Synopsis 3. There may be some other new way to do this (?) in perl6 as well.

    Update: It seems they are still wrestling with this in perl6 (see section on map), although the piping I use above is one way to disambiguate and is not available in perl5.

      Eh, I don't think the <== will help. It's too far away. The problem is that when encountering the {, perl has to decide whether what's following is a block or a hashref. And to decide that, it can only look a limited amount of tokens ahead. (2 tokens, I think). So, when it sees the { followed by a string, followed by a comma (or fat arrow), it thinks it's a hashref, as hashes are often declared as string, comma, string, comma, etc. But if it sees a unary plus, or a string followed by a dot - basically, anything that isn't a string followed by a comma, it guesses 'block'.

      Most likely, perl6 will still be a limited look-ahead parser, and not for instance something generated by Parse::RecDescent. Limited look-ahead parsers are much faster than unlimited look-ahead parsers, due to the fact they can do table lookups, and don't have to backtrack.

        Interesting. I hope *something* is done about this but it's a bit late for that ;->
Re: order in map
by osunderdog (Deacon) on May 02, 2005 at 19:54 UTC

    Forcing a list return from the block works:

     my %hash = map { ("stuff_$_" => $_) } qw(asdf qwert zxcv);

    Soon to be unemployed!

      The block always returns a list. Parens don't make lists all by themselves; something has to provide a list context.

      Anyway, my favorite:

      my %hash = map {; "stuff_$_" => $_ } qw(asdf qwert zxcv);
Re: order in map
by suaveant (Parson) on May 04, 2005 at 15:12 UTC
    Of course... thinking back on this, there is one truly important thing to remember!

    COMMENT the anomaly! Otherwise, someday, someone (you or another) will say, "why not just put that in double quotes?", and the cycle will begin anew :)

                    - Ant
                    - Some of my best work - (1 2 3)