:5hours
is a Pair
, hours => 5
is also a Pair
:
> DateTime.now.truncated-to('day').later(:5hours)
2022-02-14T05:00:00 08:00
> :5hours.WHAT
(Pair)
> DateTime.now.truncated-to('day').later(hours => 5)
2022-02-14T05:00:00 08:00
> (hours => 5).WHAT
(Pair)
However, when I create a Pair
manually, it doesn't match the signatures of later
:
> DateTime.now.truncated-to('day').later(Pair.new('hours', 5))
Cannot resolve caller later(DateTime:D: Pair:D); none of these signatures match:
(Dateish:D: *%unit --> Dateish:D)
(Dateish:D: @pairs, *%_)
in block <unit> at <unknown file> line 1
But use a vertical before the Pair
parameter is ok:
> DateTime.now.truncated-to('day').later(|Pair.new('hours', 5))
2022-02-14T05:00:00 08:00
So what's the difference between :5hours
, Pair.new('hours', 5)
and hours => 5
? Why can't pass a manually created Pair
such as Pair.new('hours', 5)
to later
method?
Aren't the following two the same thing, right?
> :5hours === Pair.new('hours', 5) === hours => 5
True
> :5hours eqv Pair.new('hours', 5) eqv hours => 5
True
> my $pair1 = Pair.new('hours', 5); dd $pair1; # Pair $pair1 = :hours(5)
> my $pair2 = :5hours; dd $pair2; # Pair $pair2 = :hours(5)
> my $pair3 = hours => 5; dd $pair3; # Pair $pair3 = :hours(5)
> my $pair4 = 'hours' => 5; dd $pair4; # Pair $pair4 = :hours(5)
CodePudding user response:
Although :5hours
and hours => 5
and :hours(5)
and Pair.new(hours,5)
and Pair.new(key => "hours", value => 5)
are all different ways to create a Pair
object, only the first three are syntactic sugar to indicate a named argument.
When you pass Pair.new("hours",5)
as an argument, it is considered to be a Positional argument. Observe:
sub foo(*@_, *%_) {
dd @_, %_
}
foo hours => 5;
# []
# {:hours(5)}
foo Pair.new("hours",5);
# [:hours(5)]
# {}
As to why this is this way? Well, sometimes you want to pass a Pair
as a positional argument. If a Pair
was always considered to be a named argument, you wouldn't be able to do so.
As to why |Pair.new("hours",5)
works as a named argument? The |
in this context, flattens the given object (which is usually a Capture
or a Hash
/Map
) into the arguments to the given subroutine. The Pair
in this case, is seen as a degenerate case of a Map
: an immutable Map
with a single key / value. Observe:
foo |Pair.new("hours",5);
# []
# {:hours(5)}
Well, probably any Associative
:-)
say Pair ~~ Associative; # True
.say for (:5hours).keys; # hours
.say for (:5hours).values; # 5
Finally, the |
in this context is technically not a Slip
, but syntactic sugar to flatten the given value into the arguments of a call.
The syntax predates the concept of a Slip
(which was introduced in 2015 during the Great List Refactor). It was only very late in 2015 that |
was OK'd by @Larry to also be used to indicate a Slip
, as they conceptually do similar things.