Home > Mobile >  Why can't pass a manually created Pair to method without a slip?
Why can't pass a manually created Pair to method without a slip?

Time:02-14

: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.

  • Related