Skip to content

Commit b9531b2

Browse files
authored
[WIP] Try to fix intro of non-string keys of Hash
1 parent 263c847 commit b9531b2

File tree

1 file changed

+59
-60
lines changed

1 file changed

+59
-60
lines changed

doc/Type/Hash.pod6

Lines changed: 59 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ You can assign to multiple keys at the same time with a slice.
113113
114114
=head2 Non-string keys
115115
116+
X<|non-string keys>X<|:{}>
117+
116118
By default keys in C<{ }> are forced to strings. To compose a hash with
117119
non-string keys, use a colon prefix:
118120
@@ -127,6 +129,63 @@ Note: The same pitfalls explained about C<{}> sometimes creating Block's also
127129
apply to C<:{}>. At this time there is no C<%()> version for creating non-string
128130
keys.
129131
132+
Hash keys are stored as L<Str> values in a normal hash. In many cases this is
133+
sufficient, but sometimes you want the hash to preserve the objects you are using
134+
as keys I<as the *exact* objects you are providing to the hash to use as keys>.
135+
In these moments you want an object hash!
136+
137+
my %intervals{Instant};
138+
my $first-instant = now;
139+
%intervals{ $first-instant } = "Our first milestone.";
140+
sleep 1;
141+
my $second-instant = now;
142+
%intervals{ $second-instant } = "Logging this Instant for spurious raisins.";
143+
for %intervals.sort -> (:$key, :$value) {
144+
state $last-instant //= $key;
145+
say "We noted '$value' at $key, with an interval of {$key - $last-instant}";
146+
$last-instant = $key;
147+
}
148+
149+
This example uses an object hash that only accepts keys of type L<Instant> to
150+
implement a rudimentary, yet type-safe, logging mechanism. We utilize a named L<state|/language/variables#The_state_Declarator>
151+
variable for keeping track of the previous C<Instant> so that we can provide an interval.
152+
153+
The whole point of object hashes is to keep keys as objects-in-themselves.
154+
Currently object hashes utilize the L<WHICH|/routine/WHICH> method of an object, which returns a
155+
unique identifier for every mutable object. This is the keystone upon which the object
156+
identity operator (L<===>) rests. Order and containers really matter here as the order of
157+
C<.keys> is undefined and one anonymous list is never L<===> to another.
158+
159+
my %intervals{Instant};
160+
my $first-instant = now;
161+
%intervals{ $first-instant } = "Our first milestone.";
162+
sleep 1;
163+
my $second-instant = now;
164+
%intervals{ $second-instant } = "Logging this Instant for spurious raisins.";
165+
say ($first-instant, $second-instant) ~~ %intervals.keys; # OUTPUT: «False␤»
166+
say ($first-instant, $second-instant) ~~ %intervals.keys.sort; # OUTPUT: «False␤»
167+
say ($first-instant, $second-instant) === %intervals.keys.sort; # OUTPUT: «False␤»
168+
say $first-instant === %intervals.keys.sort[0]; # OUTPUT: «True␤»
169+
170+
Since C<Instant> defines its own comparison methods, in our example a sort according to
171+
L<cmp> will always provide the earliest instant object as the first element in the L<List>
172+
it returns.
173+
174+
If you would like to accept any object whatsoever in your hash, you can use L<Any>!
175+
176+
my %h{Any};
177+
%h{(now)} = "This is an Instant";
178+
%h{(DateTime.now)} = "This is a DateTime, which is not an Instant";
179+
%h{"completely different"} = "Monty Python references are neither DateTimes nor Instants";
180+
181+
There is a more concise syntax which uses binding.
182+
183+
my %h := :{ (now) => "Instant", (DateTime.now) => "DateTime" };
184+
185+
The binding is necessary because an object hash is about very solid, specific objects,
186+
which is something that binding is great at keeping track of but about which assignment doesn't
187+
concern itself much.
188+
130189
=head2 Constraint value types
131190
132191
Place a type object in-between the declarator and the name to constraint the type
@@ -204,66 +263,6 @@ pairs can be accessed in the same way as with plain C<.kv>:
204263
You can also loop over a C<Hash> using
205264
L<destructuring|/type/Signature#Destructuring_Parameters>.
206265
207-
=head2 Object hashes and type constraints
208-
X<|object hash>X<|:{}>
209-
210-
Hash keys are stored as L<Str> values in a normal hash. In many cases this is
211-
sufficient, but sometimes you want the hash to preserve the objects you are using
212-
as keys I<as the *exact* objects you are providing to the hash to use as keys>.
213-
In these moments you want an object hash!
214-
215-
my %intervals{Instant};
216-
my $first-instant = now;
217-
%intervals{ $first-instant } = "Our first milestone.";
218-
sleep 1;
219-
my $second-instant = now;
220-
%intervals{ $second-instant } = "Logging this Instant for spurious raisins.";
221-
for %intervals.sort -> (:$key, :$value) {
222-
state $last-instant //= $key;
223-
say "We noted '$value' at $key, with an interval of {$key - $last-instant}";
224-
$last-instant = $key;
225-
}
226-
227-
This example uses an object hash that only accepts keys of type L<Instant> to
228-
implement a rudimentary, yet type-safe, logging mechanism. We utilize a named L<state|/language/variables#The_state_Declarator>
229-
variable for keeping track of the previous C<Instant> so that we can provide an interval.
230-
231-
The whole point of object hashes is to keep keys as objects-in-themselves.
232-
Currently object hashes utilize the L<WHICH|/routine/WHICH> method of an object, which returns a
233-
unique identifier for every mutable object. This is the keystone upon which the object
234-
identity operator (L<===>) rests. Order and containers really matter here as the order of
235-
C<.keys> is undefined and one anonymous list is never L<===> to another.
236-
237-
my %intervals{Instant};
238-
my $first-instant = now;
239-
%intervals{ $first-instant } = "Our first milestone.";
240-
sleep 1;
241-
my $second-instant = now;
242-
%intervals{ $second-instant } = "Logging this Instant for spurious raisins.";
243-
say ($first-instant, $second-instant) ~~ %intervals.keys; # OUTPUT: «False␤»
244-
say ($first-instant, $second-instant) ~~ %intervals.keys.sort; # OUTPUT: «False␤»
245-
say ($first-instant, $second-instant) === %intervals.keys.sort; # OUTPUT: «False␤»
246-
say $first-instant === %intervals.keys.sort[0]; # OUTPUT: «True␤»
247-
248-
Since C<Instant> defines its own comparison methods, in our example a sort according to
249-
L<cmp> will always provide the earliest instant object as the first element in the L<List>
250-
it returns.
251-
252-
If you would like to accept any object whatsoever in your hash, you can use L<Any>!
253-
254-
my %h{Any};
255-
%h{(now)} = "This is an Instant";
256-
%h{(DateTime.now)} = "This is a DateTime, which is not an Instant";
257-
%h{"completely different"} = "Monty Python references are neither DateTimes nor Instants";
258-
259-
There is a more concise syntax which uses binding.
260-
261-
my %h := :{ (now) => "Instant", (DateTime.now) => "DateTime" };
262-
263-
The binding is necessary because an object hash is about very solid, specific objects,
264-
which is something that binding is great at keeping track of but about which assignment doesn't
265-
concern itself much.
266-
267266
=head2 In place editing of values
268267
269268
There may be times when you would like to modify the values of a hash while iterating over them.

0 commit comments

Comments
 (0)