Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this map block contain an apparently useless +?

Tags:

map

perl

While browsing the source code I saw the following lines:

my @files_to_keep = qw (file1 file2);
my %keep = map { + $_ => 1 } @files_to_keep;

What does the + do in this code snippet? I used Data::Dumper to see whether taking out the plus sign does anything, but the results were the same:

  $ perl cleanme.pl
$VAR1 = {
          'file1' => 1,
          'file2' => 1
        };
like image 943
Alby Avatar asked Mar 07 '13 17:03

Alby


2 Answers

The unary-plus operator simply returns its operand unchanged. Adding one doesn't even change the context.

In the example you gave, it is completely useless. But there are situations where it is useful to make the next token something that's undeniably an operator.


For example, map has two syntaxes.

map EXPR, LIST

and

map BLOCK LIST

A block starts with {, but so can an expression. For example, { } can be a block or a hash constructor.

So how can map tell the difference? It guesses. Which means it's sometimes wrong.

One occasion where is guesses wrong is the following:

map { $_ => 1 }, @list

You can prod it in to guessing correctly using + or ;.

map {; ...     # BLOCK
map +{ ...     # EXPR

So in this case, you could use

map +{ foo => $_ }, @list

Note that you could also use the following:

map({ foo => $_ }, @list)

Another example is when you omit the parens around arguments, and the first argument expression starts with a paren.

print ($x+$y)*2;    # Same as: 2 * print($x+$y)

It can be fixed using

print +($x+$y)*2;

But why pile on a hack just to avoid parens? I prefer

print(($x+$y)*2);
like image 199
ikegami Avatar answered Nov 15 '22 18:11

ikegami


This is used to prevent a parsing problem. The plus symbol forces the interpreter to behave like a normal block and not an expression.

The fear is that perhaps you are trying to create a hashreference using the other (expression) formulation of map like so.

@array_of_hashrefs = map {  "\L$_" => 1  }, @array

Notice the comma. Then if the parser guesses that you are doing this given the statement in the OP there will a syntax error for missing the comma! To see the difference try quoting "$_". For whatever reason, the parser takes this as enough to trigger the expression behavior.

Yes its an oddity. Therefore many extra-paranoid Perl programmers toss in the extra plus sign more often than needed (me included).

Here are the examples from the map documentation.

%hash = map {  "\L$_" => 1  } @array  # perl guesses EXPR.  wrong
%hash = map { +"\L$_" => 1  } @array  # perl guesses BLOCK. right
%hash = map { ("\L$_" => 1) } @array  # this also works
%hash = map {  lc($_) => 1  } @array  # as does this.
%hash = map +( lc($_) => 1 ), @array  # this is EXPR and works!
%hash = map  ( lc($_), 1 ),   @array  # evaluates to (1, @array)

For a fun read (stylistically) and a case where the parser gets it wrong read this: http://blogs.perl.org/users/tom_wyant/2012/01/the-case-of-the-overloaded-curlys.html

like image 33
Joel Berger Avatar answered Nov 15 '22 19:11

Joel Berger