This is a bit of unexpected behavior that's likely to bite beginners. First, is this intended? Second, what other things does Perl 6 use to guess which object to create? Does it start off thinking it's Block or Hash and change later, or does it decide on the end?
You can construct a Hash with braces and the fat arrow:
my $color-name-to-rgb = {
'red' => 'FF0000',
};
put $color-name-to-rgb.^name; # Hash
Using the other Pair notation creates a Hash too.
my $color-name-to-rgb = {
:red('FF0000'),
};
But, absent the fat arrow, I get a Block instead:
my $color-name-to-rgb = {
'red', 'FF0000',
};
put $color-name-to-rgb.^name; # Block
The Hash docs only mention that using $_
inside the braces creates a Block.
There are other ways to define a hash, but I'm asking about this particular bit of syntax and not looking for the workarounds I already know about.
$ perl6 -v
This is Rakudo version 2017.04.3 built on MoarVM version 2017.04-53-g66c6dda
implementing Perl 6.c.
TL;DR This answer starts with the simplest description I think is reasonable then attempts to cover everything in precise detail. Please let me know in the comments if anything is too complicated or missing.
This rule only applies in term position
Only braced code ({...}
) that is in term position1 is subject to this DWIM/WAT.2
In these examples the {...}
is not in term position:
if True { ... } # always a block
class foo { ... } # always a package
put bar{ ... } # always a hash index
For the rest of this answer {...}
only means braced code in term position.
Simple description of DWIM/WAT for {...}
in term position
By default {...}
is a Block
. Also, if it has a signature, multiple statements, or a declaration of an identifier, then it's a Block
.
Otherwise, if {...}
contains just a list of zero or more values starting directly with a %
sigil'd variable (eg %foo
) or a Pair
literal (eg :bar
) then it's a Hash
.
An explicit signature means it's a Block
Some braced code has an explicit signature, i.e. it has explicit parameters such as $foo
below. It always constructs a Block
no matter what's inside the braces:
say WHAT { key => $foo, 'a', 'b' } # (Hash)
say WHAT -> $foo { key => $foo, 'a', 'b' } # (Block)
An implicit signature also means it's a Block
Some braced code has an implicit signature:
Explicit use of a "pronoun" inside braced code means it's a Block
with an implicit signature if it doesn't already have an explicit signature. The pronouns are $_
, @_
, and %_
.
Implicit use of $_
inside braced code via a method call without an explicit invocant means it's a Block
with an implicit signature. In other words, even { .foo }
has a signature ((;; $_? is raw)
) due to the .foo
.
Use of an explicit "placeholder" variable (e.g. $^foo
) inside braced code also means it's a Block
with an implicit signature (with a $foo
parameter in it).
As with an explicit signature, if braced code has an implicit signature then it always constructs a Block
no matter what's inside the braces:
say WHAT { key => $_ } # (Block)
say WHAT { key => 'value', .foo, .foo } # (Block)
Multiple top level statements mean it's a Block
say WHAT { :foo; (do 'a'), (do 'b') } # (Block)
say WHAT { :foo, (do 'a'), (do 'b') } # (Hash)
The second line contains multiple statements but they're producing values within a list that's the single top level statement.
A top level declaration of an identifier mean it's a Block
say WHAT { :foo, (my $bar), $baz } # (Block)
say WHAT { :foo, {my $bar}, $baz } # (Hash)
The last line contains a Block
as a key that contains a declaration (my $bar
). But that declaration belongs to the inner Block
, not the outer braced code. So the inner Block
is just a value as far as the outer braced code is concerned, and thus the outer braced block is still interpreted as a Hash
.
Still Block
s
my $bar = key => 'value';
say WHAT { $bar, %baz } # (Block)
say WHAT { |%baz } # (Block)
say WHAT { %@quux } # (Block)
None of the above start with a %
sigil'd variable or literal pair.
When it's a Hash
Braced code that doesn't fall into any of the foregoing situations that force it to be a Block
, and which is just a list of zero or more values that start with either a %
sigil'd variable or a Pair
literal constructs a Hash
:
say WHAT { %foo } # (Hash)
say WHAT { %foo, ... } # (Hash)
say WHAT { foo => 42, ... } # (Hash)
say WHAT { :foo, ... } # (Hash)
say WHAT { key => $foo, 'a', 'b' } # (Hash)
say WHAT { 'a', 'b', key => $foo } # (Block)
The last block above doesn't start with a %foo
or literal pair.
say WHAT { %foo, 'a', 'b' } # (Hash)
say WHAT { Pair.new('key',$foo), # Pair.new is NOT a literal
'a', 'b' } # (Block)
The second block above doesn't start with a %foo
or literal pair.
To force Block
or Hash
interpretation
To write an empty Block
, write {;}
. To write an empty Hash
, write {}
.
To force braced code to construct a Block
instead of a Hash
, write a ;
at the start i.e. {; ... }
.
To force braced code to construct a Hash
instead of a Block
, follow the rules explained above or write %(...)
instead of {...}
.
Footnotes
1 See comments below answer about term position.
2 A worthwhile DWIM must work in most coders' favor most of the time and its associated WATs must be acceptable to the community. (WAT refers to a dev's surprise when a DWIM doesn't do what they meant. For every DWIM there are one or more WATs.)
Acceptable WATs have barks worse than their bites. Like all DWIMs, this one can require community vigilance and response to ensure it remains a net win rather than warranting deprecation, and community member opinions differ on how much its bite hurts. cf my perspective vs Sam's answer to this question.
The preferred Perl6 way is to use %( )
to create hashes.
my $color-name-to-rgb = %(
'red', 'FF0000',
);
I would not recommend people use braces to create hashes, ever. If they want to make a hash then %( )
is the proper way to do it.
If you are coming from the Perl 5 world it's best to just get in the habit of using %( )
instead of { }
when creating a Hash.