Skip to content

Commit 1b64539

Browse files
committed
A slightly gentler walk through :D/:U constraint examples
1 parent 5c99779 commit 1b64539

File tree

1 file changed

+42
-8
lines changed

1 file changed

+42
-8
lines changed

doc/Type/Signature.pod6

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,17 @@ part of the L<colon-pair|/type/Pair>.
214214
type constraint,:D;type constraint,:U;type constraint,:_>
215215
216216
Normally, a type constraint only checks whether the value of the parameter is of the
217-
correct type.
217+
correct type. Crucially, both I<object instances> and I<type objects> will satisfy
218+
such a constraint as illustrated below:
219+
220+
say 42.WHAT # OUTPUT: «(Int)␤»
221+
say 42 ~~ Int # OUTPUT: «True␤»
222+
say Int ~~ Int # OUTPUT: «True␤»
223+
224+
Note how both C<42> and C<Int> satisfy the match.
225+
226+
Sometimes we need to distinguish between these object instances (C<42>)
227+
and type objects (C<Int>). Consider the following code:
218228
219229
sub limit-lines(Str $s, Int $limit) {
220230
my @lines = $s.lines;
@@ -229,10 +239,20 @@ correct type.
229239
# (Str:D $: *%_)»
230240
say limit-lines "a \n b", Int # Always returns the max number of lines
231241
232-
In the code above, we really only want to deal with string instances, not
233-
type objects. To do this, we use the C<:D> type constraint. This constraint
234-
checks the value passed is an I<object instance>, in a similar fashion to calling
235-
the C<.DEFINITE> method on the value:
242+
Here we really only want to deal with string instances, not
243+
type objects. To do this, we can use the C<:D> type constraint. This constraint
244+
checks that the value passed is an I<object instance>, in a similar fashion to calling
245+
its L<DEFINITE|/language/mop#DEFINITE> method.
246+
247+
To warm up, let's apply C<:D> to the right hand side of our humble C<Int> example:
248+
249+
say 42 ~~ Int:D # OUTPUT: «True␤»
250+
say Int ~~ Int:D # OUTPUT: «False␤»
251+
252+
Note how only C<42> matches C<Int:D> in the above.
253+
254+
Returning to C<limit-lines>, we can now amend its signature to catch the error
255+
early:
236256
237257
sub limit-lines(Str:D $s, Int $limit) { };
238258
say limit-lines Str, 3;
@@ -243,10 +263,18 @@ the C<.DEFINITE> method on the value:
243263
This is much better than the way the program failed before, since here the
244264
reason for failure is clearer.
245265
246-
It's also possible that type objects are the only ones that make
266+
It's also possible that I<type objects> are the only ones that make
247267
sense for a routine to accept. This can be done with the C<:U> type
248-
constraint, which checks the value passed if it is a I<type object>,
249-
rather than an object instance.
268+
constraint, which checks whether the value passed is a type object
269+
rather than an object instance. Here's our C<Int> example again, this
270+
time with C<:U> applied:
271+
272+
say 42 ~~ Int:U # OUTPUT: «False␤»
273+
say Int ~~ Int:U # OUTPUT: «True␤»
274+
275+
Now C<42> fails to match C<Int:U> while C<Int> succeeds.
276+
277+
Here's a more practical example:
250278
251279
sub can-turn-into(Str $string, Any:U $type) {
252280
return so $string.$type;
@@ -257,6 +285,12 @@ rather than an object instance.
257285
say can-turn-into("a string", Num);
258286
# OUTPUT: True True True False
259287
288+
Calling C<can-turn-into> with an object instance as its second parameter
289+
will yield a constraint violation as intended:
290+
291+
say can-turn-into("a string", 123);
292+
# OUTPUT: «Parameter '$type' of routine 'can-turn-into' must be a type object of type 'Any', not an object instance of type 'Int'...»
293+
260294
For explicitly indicating the normal behaviour, C<:_> can be used, but this is
261295
unnecessary. C<:(Num:_ $)> is the same as C<:(Num $)>.
262296

0 commit comments

Comments
 (0)