This is a bit of unexpected behavior that's likely to bite beginners. First, is this intended? Second, what other things does Raku 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.
Hash
Your question1 and this answer only apply to braced blocks in term position2.
Braced code that precisely follows the rule explained below constructs a Hash
:
say WHAT { } # (Hash)
say WHAT { %foo } # (Hash)
say WHAT { %foo, ... } # (Hash)
say WHAT { foo => 42, ... } # (Hash)
say WHAT { :foo, ... } # (Hash)
say WHAT { key => $foo, ... } # (Hash)
If the block is empty, or contains just a list whose first element is a %
sigil'd variable (eg %foo
) or a literal pair (eg :bar
), and it does not have a signature or include top level statements, it's a Hash
. Otherwise it's a Block
.
Block
or Hash
interpretationTo force a {...}
term to construct a Block
instead of a Hash
, write a ;
at the start i.e. { ; ... }
.
To write an empty Block
term, write {;}
.
To write an empty Hash
term, write {}
.
To force a {...}
term to construct a Hash
instead of a Block
, follow the rule (explained in detail in the rest of this answer), or write %(...)
instead.
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)
Block
Some braced code has an implicit signature that is generated due to some explicit choice of coding within the block:
Use of a "pronoun" inside {...}
means it's a Block
with a signature (an implicit signature if it doesn't already have an explicit one). The pronouns are $_
, @_
, and %_
.
This includes implied use of $_
inside {...}
due to a .method
call with no left hand side argument. In other words, even { .foo }
has a signature ((;; $_? is raw)
) due to .foo
's lack of a left hand side argument.
Use of a "placeholder" variable (e.g. $^foo
).
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, .bar } # (Block)
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 individual elements of a list that's the single top level expression.
Block
A declaration is a statement, but I've included this section just in case someone doesn't realize that.
say WHAT { :foo, $baz, {my $bar} } # (Hash)
say WHAT { :foo, $baz, (my $bar) } # (Block)
The first line contains a Block
as a key that contains a declaration (my $bar
). But that declaration belongs to the inner {my $bar}
Block
, not the outer {...}
. So the inner Block
is just a value as far as the outer {...}
is concerned, and thus that outer braced code is still interpreted as a Hash
.
In contrast the second line declares a variable directly within the outer {...}
. So it's a Block
.
Block
s, not Hash
sRecall that, to be a Hash
, the content of braced code must be a list that begins with either a %
sigil'd variable or a literal pair. So these all produce Block
s:
my $bar = key => 'value';
say WHAT { $bar, %baz } # (Block)
say WHAT { |%baz } # (Block)
say WHAT { %@quux } # (Block)
say WHAT { 'a', 'b', key => $foo } # (Block)
say WHAT { Pair.new: 'key', $foo } # (Block)
1 This "Hash
or Block
?" question is an example of DWIM design. In Raku culture, good DWIM design is considered a good thing. But every DWIM comes with corresponding WATs3. The key to good DWIM design is ensuring that, in general, WATs' barks are worse than their bites4; and that the barks are useful5; and that the net benefits of the DWIM are considered to far outweigh all the barking and biting.6
2 A term is Raku's analog of a noun or noun phrase in English. It's a value.
Examples of braced blocks that are terms:
.say given { ... } # closure? hash?
say 42, { ... } # closure? hash?
Examples of braced blocks that are not terms:
if True { ... } # always a closure
class foo { ... } # always a package
put bar{ ... } # always a hash index
This answer only discusses braced blocks that are terms. For more details about terms, or more specifically "term position" (places in the grammar where a braced block will be interpreted as a term), see the comments below this answer.
3WAT refers to a dev's incredulous surprise when something seems crazy to them. It's known that, even for well designed DWIMs, for each one that works for most folk, most of the time, there are inevitably one or more related WATs that surprise some folk, some of the time, including some of the same folk who at other times benefit from the DWIM.
4 The bite of the WATs related to this DWIM varies. It's typically a bark (error message) that makes the problem obvious. But it can also be much more obscure:
say { a => 42 }() ; # No such method 'CALL-ME' for invocant of type 'Hash' WAT? Oh.
say { a => $_ }<a> ; # Type Block does not support associative indexing. WAT? Oh.
say { a => $_, b => 42, c => 99 } .elems # 1 WAT?????
5 A "bark" is an error message or warning in documentation. These can often be improved. cf Lock.protect({}) fails, but with surprising message.
6 Community member opinions differ on whether DWIM design in general, or any given DWIM in particular, is worth it. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With