type constraint :D
Documentation for type constraint :D, assembled from the following types:
Normally, a type constraint only checks whether the value of the parameter is of the correct type.
sub limit-lines(Str , Int )say (limit-lines "a \n b \n c \n d \n", 3).perl; # "a \n b \n c \n d "say limit-lines Str, 3;CATCH ;# OUTPUT: «X::Multi::NoMatch: Cannot resolve caller lines(Str: ); none of these signatures match:# (Str:D $: :$count!, *%_)# (Str:D $: $limit, *%_)# (Str:D $: *%_)»say limit-lines "a \n b", Int # Always returns the max number of lines
In the code above, we really only want to deal with string instances, not type objects. To do this, we use the
:D type constraint. This constraint checks the value passed is an object instance, in a similar fashion to calling the
.DEFINITE method on the value:
sub limit-lines(Str , Int ) ;say limit-lines Str, 3;CATCH ;# OUTPUT: «Parameter '$s' of routine 'limit-lines' must be an object instance of type 'Str',# not a type object of type 'Str'. Did you forget a '.new'?»
This is much better than the way the program failed before, since here the reason for failure is clearer.
It's also possible that type objects are the only ones that make sense for a routine to accept. This can be done with the
:U type constraint, which checks the value passed if it is a type object, rather than an object instance.
sub can-turn-into(Str , Any )say can-turn-into("3", Int);say can-turn-into("6.5", Int);say can-turn-into("6.5", Num);say can-turn-into("a string", Num);# OUTPUT: True True True False
For explicitly indicating the normal behaviour,
:_ can be used, but this is unnecessary.
:(Num:_ $) is the same as
To recap, here is a quick illustration of these type constraints, also known collectively as type smileys:
# Checking a type objectsay Int ~~ Any; # OUTPUT: «False␤»say Int ~~ Any; # OUTPUT: «True␤»say Int ~~ Any; # OUTPUT: «True␤»# Checking an object instancesay 42 ~~ Any; # OUTPUT: «True␤»say 42 ~~ Any; # OUTPUT: «False␤»say 42 ~~ Any; # OUTPUT: «True␤»# Checking a user-supplied class;say Foo ~~ Any; # OUTPUT: «False␤»say Foo ~~ Any; # OUTPUT: «True␤»say Foo ~~ Any; # OUTPUT: «True␤»my = Foo.new;say ~~ Any; # OUTPUT: «True␤»say ~~ Any; # OUTPUT: «False␤»say ~~ Any; # OUTPUT: «True␤»
The Classes and Objects document further elaborates on the concepts of instances and type objects and discovering them with the
Keep in mind all parameters have values; even optional ones have default defaults that are the type object of the constrained type for explicit type constraints. If no explicit type constraint exists, the default default is an Any type object for methods, submethods, and subroutines, and a Mu type object for blocks. This means that if you use the
:D type smiley, you'd need to provide a default value or make the parameter required. Otherwise, the default default would be a type object, which would fail the definiteness constraint.
sub divide (Int : = 2, Int :!)divide :1a, :2b; # OUTPUT: «0.5␤»