In the Perl doc, there is a section about .postfix/.postcircumfix, it says that
In most cases, a dot may be placed before a postfix or postcircumfix:
my @a;
@a[1, 2, 3];
@a.[1, 2, 3]; # Same
Technically, not a real operator; it's syntax special-cased in the compiler.
I tried myself:
> my @a = 1,2,3,4,5
> @a[1] # 2
> @a.[1] # 2
> my %a = Perl => 6, Python => 3, PHP => 7
> %a<Perl> #6
> %a.<Perl> #6
> my @weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
> @weekdays.antipairs.hash{'Sunday'} # 6, I expected it to be syntax wrong, but it did work!
> @weekdays.antipairs.hash.{'Sunday'} # 6, seems visual clarity or brevity
So, what does the dot before a postfix or postcircumfix in Perl 6 mean? How on earth did it do that? I'm curious about that. Thanks.
An expression in Perl 6 is parsed as termish
things with infixish
things between them. A termish
is in turn defined as zero or more prefixish
things, followed by the term itself, followed by zero or more postfixish
things. The postfixish
takes in all of:
.foo
)++
)[42]
in @a[42]
)>>
) on these to distribute them across a data structureSince it just looks for zero or more of them, then you can freely interleave method calls and hash and array indexes. This explains why @weekdays.antipairs.hash{'Sunday'}
parses fine (and why @weekdays.antipairs.hash<Sunday>
would also work, and even @weekdays.antipairs.hash<Sunday>.say
is fine too).
As for the .
, the grammar simply accepts and ignores a .
before a postfix
or a postcircumfix
. Here's a slightly cut-down version of the parser, that I've annotated a bit to explain what the pieces are.
token postfixish {
<!stdstopper>
# If we're not in a string interpolation, allow unspace (that's
# where you write `\ ++`, for example, allowing spreading
# postfixish things over multiple lines).
[ <!{ $*QSIGIL }> [ <.unsp> | '\\' ] ]?
# Here we match the >> for doing a hyper. Note that it accepts
# but disregards a '.' before it. It's not captured at all and
# doesn't affect the code that is compiled.
[ ['.' <.unsp>?]? <postfix_prefix_meta_operator> <.unsp>?]**0..1
[
| <OPER=postfix>
# When there'd be no confusion with a method call, a '.' is
# also accepted and disregarded before a postfix operator
| '.' <?before \W> <OPER=postfix> ## dotted form of postfix operator (non-wordy only)
| <OPER=postcircumfix>
# Ditto here for recognized postcircumfixes
| '.' <?[ [ { < ]> <OPER=postcircumfix>
| <OPER=dotty>
| <OPER=privop>
]
}
Thus the .
means nothing at all in this context. The parser simply accepts it and then moves on to look for the thing it actually cares about at that point.
One other thing worth noting is that postfix and postcircumfix operators all work after a dotty term too, operating on $_
. Thus:
my @xs = 1..10;
.++ for @xs;
say @xs;
Will produce:
[2 3 4 5 6 7 8 9 10 11]
Here's a postcircumfix example:
my %h = a => 1, b => 2, c => 3;
say .<a> + .<c> given %h;
Which produces 4
.
Perl 6 syntax is generally designed to make it easy to shift code from one form to another, and accepting the .
in places even where it's not strictly needed eases that a little (so one could refactor to say %h1.<a> + %h2.<b>;
and the parser will be fine with it). It may also be helpful for learning purposes to consider %h<a>
short for %h.<a>
, which would in turn make .<a> given %h
a little less of a surprise.
The extra space afforded by the .
may also aid clarity, especially if one was to stack multiple postfixes, and could even - should a language extension for some reason decide to define some "interesting" terms or postfix operators - serve as a means to disambiguate.
It actually does matter when you have a sub that returns a Callable
.
sub foo { 'hello' }
sub bar { &foo; }
bar.WHAT # (Sub)
bar().WHAT # (Sub)
bar.().WHAT # (Str)
bar()().WHAT # (Str)
bar().().WHAT # (Str)
bar.().().WHAT # No such method 'CALL-ME' for invocant of type 'Str'
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