Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
367 lines (241 sloc) 10.4 KB
=begin pod :kind("Type") :subkind("class") :category("composite")
=TITLE class Pair
=SUBTITLE Key/value pair
class Pair does Associative {}
Consists of two parts, a I<key> and a I<value>. C<Pair>s can be seen as the
atomic units in C<Hash>es, and they are also used in conjunction with named
arguments and parameters.
X<|colon pair (Pair)>
X<|:> X«| => » X<|:!> X<|:$>
There are many syntaxes for creating C<Pair>s:
Pair.new('key', 'value'); # The canonical way
'key' => 'value'; # this...
:key<value>; # ...means the same as this
:key<value1 value2>; # But this is key => <value1 value2>
:foo(127); # short for foo => 127
:127foo; # the same foo => 127
Note that last form supports Non-ASCII numerics as well:
# use MATHEMATICAL DOUBLE-STRUCK DIGIT THREE
say (:𝟛math-three); # OUTPUT: «math-three => 3␤»
You can also use an I<identifier-like literal> as key; this will not need the
quotes as long as it follows the syntax of
L<ordinary identifiers|/syntax/identifiers#Ordinary_identifiers>:
(foo => 127) # the same foo => 127
Variants of this are
:key; # same as key => True
:!key; # same as key => False
And this other variant, to be used in routine invocation
=begin code
sub colon-pair( :$key-value ) {
say $key-value;
}
my $key-value = 'value';
colon-pair( :$key-value ); # OUTPUT: «value␤»
colon-pair( key-value => $key-value ); # OUTPUT: «value␤»
=end code
X<|colon list (Pair)>
Colon pairs can be chained without a comma to create a List of Pairs. Depending
on context you may have to be explicit when assigning colon lists.
sub s(*%h){ say %h.perl };
s :a1:b2;
# OUTPUT: «{:a1, :b2}␤»
my $manna = :a1:b2:c3;
say $manna.^name;
# OUTPUT: «Pair␤»
$manna = (:a1:b2:c3);
say $manna.^name;
# OUTPUT: «List␤»
Any variable can be turned into a C<Pair> of its name and its value.
my $bar = 10;
my $p = :$bar;
say $p; # OUTPUT: «bar => 10␤»
It is worth noting that when assigning a L<Scalar|/type/Scalar> as value of a
C<Pair> the value holds the container of the value itself. This means that it is
possible to change the value from outside of the C<Pair> itself:
=begin code
my $v = 'value A';
my $pair = a => $v;
$pair.say; # OUTPUT: «a => value A␤»
$v = 'value B';
$pair.say; # OUTPUT: «a => value B␤»
=end code
Please also note that this behavior is totally unrelated to the way used to
build the C<Pair> itself (i.e., explicit usage of C<new>, use of colon, fat
arrow), as well as if the C<Pair> is bound to a variable.
It is possible to change the above behavior forcing the C<Pair> to remove the
scalar container and to hold the effective value itself via the method
L<freeze|/type/Pair#method_freeze>:
=begin code
my $v = 'value B';
my $pair = a => $v;
$pair.freeze;
$v = 'value C';
$pair.say; # OUTPUT: «a => value B␤»
=end code
As Pair implements L<Associative|/type/Associative> role, its value can be
accessed using Associative subscription operator, however, due to X<Pair>'s
singular nature, the pair's value will be only returned for the pair's key.
L<Nil|/type/Nil> object will be returned for any other key. Subscript
adverbs such as X<:exists> can be used on Pair.
=for code
my $pair = a => 5;
say $pair<a>; # OUTPUT: «5␤»
say $pair<a>:exists; # OUTPUT: «True␤»
say $pair<no-such-key>; # OUTPUT: «Nil␤»
=head1 Methods
=head2 method new
Defined as:
multi method new(Pair: Mu $key, Mu $value)
multi method new(Pair: Mu :$key, Mu :$value)
Constructs a new L<Pair|/type/Pair> object.
=head2 method ACCEPTS
Defined as:
multi method ACCEPTS(Pair:D $: %topic)
multi method ACCEPTS(Pair:D $: Pair:D $topic)
multi method ACCEPTS(Pair:D $: Mu $topic)
If C<%topic> is an L<Associative|/type/Associative>, looks up the value using invocant's key in
it and checks invocant's value C<.ACCEPTS> that value:
say %(:42a) ~~ :42a; # OUTPUT: «True␤»
say %(:42a) ~~ :10a; # OUTPUT: «False␤»
If C<$topic> is another L<Pair|/type/Pair>, checks the invocant's value
C<.ACCEPTS> the C<$topic>'s value. Note that the keys are not considered and can
be different:
say :42a ~~ :42a; # OUTPUT: «True␤»
say :42z ~~ :42a; # OUTPUT: «True␤»
say :10z ~~ :42a; # OUTPUT: «False␤»
If C<$topic> is any other value, the invocant C<Pair>'s key is treated as a method name.
This method is called on C<$topic>, the L«boolean|/routine/Bool» result of which is compared
against the invocant C<Pair>'s L«boolean|/routine/Bool» value. For example, primality can
be tested using smartmatch:
say 3 ~~ :is-prime; # OUTPUT: «True␤»
say 3 ~~ is-prime => 'truthy'; # OUTPUT: «True␤»
say 4 ~~ :is-prime; # OUTPUT: «False␤»
This form can also be used to check
L<Bool|/type/Bool> values of multiple methods on the same object, such as
L<IO::Path|/type/IO::Path>, by using L<Junctions|/type/Junction>:
say "foo" .IO ~~ :f & :rw; # OUTPUT: «False␤»
say "/tmp".IO ~~ :!f; # OUTPUT: «True␤»
say "." .IO ~~ :f | :d; # OUTPUT: «True␤»
=head2 method antipair
Defined as:
method antipair(--> Pair:D)
Returns a new C<Pair> object with key and value exchanged.
my $p = (6 => 'Perl').antipair;
say $p.key; # OUTPUT: «Perl␤»
say $p.value; # OUTPUT: «6␤»
=head2 method key
Defined as:
multi method key(Pair:D:)
Returns the I<key> part of the C<Pair>.
my $p = (Perl => 6);
say $p.key; # OUTPUT: «Perl␤»
=head2 method value
Defined as:
multi method value(Pair:D:) is rw
Returns the I<value> part of the C<Pair>.
my $p = (Perl => 6);
say $p.value; # OUTPUT: «6␤»
=head2 infix cmp
Defined as:
multi sub infix:<cmp>(Pair:D, Pair:D)
The type-agnostic comparator; compares two C<Pair>s. Compares first their
I<key> parts, and then compares the I<value> parts if the keys are equal.
my $a = (Apple => 1);
my $b = (Apple => 2);
say $a cmp $b; # OUTPUT: «Less␤»
=head2 method fmt
Defined as:
multi method fmt(Pair:D: Str:D $format --> Str:D)
Takes a I<format string>, and returns a string the I<key> and I<value>
parts of the C<Pair> formatted. Here's an example:
my $pair = :Earth(1);
say $pair.fmt("%s is %.3f AU away from the sun")
# OUTPUT: «Earth is 1.000 AU away from the sun␤»
For more about format strings, see L<sprintf|/routine/sprintf>.
=head2 method kv
Defined as:
multi method kv(Pair:D: --> List:D)
Returns a two-element C<List> with the I<key> and I<value> parts of
C<Pair>, in that order. This method is a special case of the same-named
method on C<Hash>, which returns all its entries as a list of keys and
values.
my $p = (Perl => 6);
say $p.kv[0]; # OUTPUT: «Perl␤»
say $p.kv[1]; # OUTPUT: «6␤»
=head2 method pairs
Defined as:
multi method pairs(Pair:D:)
Returns a list of one C<Pair>, namely this one.
my $p = (Perl => 6);
say $p.pairs.^name; # OUTPUT: «List␤»
say $p.pairs[0]; # OUTPUT: «Perl => 6␤»
=head2 method antipairs
Defined as:
multi method antipairs(Pair:D:)
Returns a L<List|/type/List> containing the L<antipair|/type/Pair#method_antipair>
of the invocant.
my $p = (6 => 'Perl').antipairs;
say $p.^name; # OUTPUT: «List␤»
say $p.first; # OUTPUT: «Perl => 6␤»
say $p.first.^name; # OUTPUT: «Pair␤»
=head2 method invert
Defined as:
method invert(Pair:D: --> Seq:D)
Returns a L<Seq|/type/Seq>. If the C<.value> of the invocant is I<NOT> an
L<Iterable|/type/Iterable>, the L<Seq|/type/Seq> will contain a single L<Pair|/type/Pair> whose
C<.key> is the C<.value> of the invocant and whose C<.value> is the C<.key> of
the invocant:
:foo<bar>.invert.perl.say; # OUTPUT: «(:bar("foo"),).Seq»
If invocant's C<.value> I<is> an L<Iterable|/type/Iterable>, the returned L<Seq|/type/Seq>
will contain the same number of L<Pair|/type/Pair>s as items in the C<.value>, with each
of those items a C<.key> of a pair and the C<.key> of the invocant the C<.value>
of that pair:
:foo<Perl is great>.invert.perl.say;
# OUTPUT: «(:Perl("foo"), :is("foo"), :great("foo")).Seq»
:foo{ :42a, :72b }.invert.perl.say;
# OUTPUT: «((:a(42)) => "foo", (:b(72)) => "foo").Seq»
To perform the exact C<.key> and C<.value> swap, use
L«C<.antipair> method|/type/Pair#method_antipair».
=head2 method keys
Defined as:
multi method keys(Pair:D: --> List:D)
Returns a L<List|/type/List> containing the L<key|/type/Pair#method_key>
of the invocant.
say ('Perl' => 6).keys; # OUTPUT: «(Perl)␤»
=head2 method values
Defined as:
multi method values(Pair:D: --> List:D)
Returns a L<List|/type/List> containing the L<value|/type/Pair#method_value>
of the invocant.
say ('Perl' => 6).values; # OUTPUT: «(6)␤»
=head2 method freeze
Defined as:
method freeze(Pair:D:)
Makes the I<value> of the C<Pair> read-only, by removing it from its L<Scalar container|/language/containers#Scalar_containers>, and returns it.
my $str = "apple";
my $p = Pair.new('key', $str);
$p.value = "orange"; # this works as expected
$p.say; # OUTPUT: «key => orange␤»
$p.freeze.say; # OUTPUT: «orange␤»
$p.value = "a new apple"; # Fails
CATCH { default { put .^name, ': ', .Str } };
# OUTPUT: «X::Assignment::RO: Cannot modify an immutable Str (apple)␤»
B<NOTE:> this method is deprecated as of B<6.d> language version. Instead,
create a new C<Pair>, with a L<decontainerized|/language/glossary#decont> key/value.
=for code :preamble<my $p>
$p.=Map.=head.say; # OUTPUT: «orange␤»
=head2 method Str
Defined as:
multi method Str(Pair:D: --> Str:D)
Returns a string representation of the invocant formatted
as I<key ~ \t ~ value>.
my $b = eggs => 3;
say $b.Str; # OUTPUT: «eggs 3␤»
=head2 method Pair
Defined as:
method Pair()
Returns the invocant Pair object.
my $pair = eggs => 3;
say $pair.Pair === $pair; # OUTPUT: «True␤»
=end pod
# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
You can’t perform that action at this time.