In Perl 6 you can specify a type that a type can be coerced to. For example, you need an Int
but get something else that can convert to an Int
. This is handy when you don't want separate candidates for Int
and Str
where the string represents an integer value.
But, it seems that the conversion is a bit aggressive because the conversion not only changes the type but is willing to change the data. It's partly a problem of the conflation of changing types and an expected operation to truncate a number to an integer. Conceptually those are different ideas but they are intertwined in Str.Int
(actually sandwiching a side trip to Numeric
):
sub foo ( Int:D() $n ) { put "Got <$n> of type {$n.^name}" }
foo( 80 ); # Got <80> of type Int
foo( '99' ); # Got <99> of type Int
foo( 1.5 ); # Got <1> of type Int
foo( '1.5' ); # Got <1> of type Int
Trying to limit this to Str
isn't any better:
sub foo ( Int:D(Str:D) $n ) { put "Got <$n> of type {$n.^name}" }
foo( '1.5' ); # Got <1> of type Int
I could make some adapters which seems the easiest to understand:
multi foo ( Int:D $n ) {
put "Got <$n> of type {$n.^name}"
}
multi foo ( Str:D $n where { $^n.Int == $^n.Numeric } ) {
foo( $n.Int );
}
foo( '1.5' ); # Cannot resolve ...
And I can probably come up with some subsets but that's not any more satisfying. So the trick is, can I coerce like this without changing the value (even if it changes representation)?
It turns out that this feature is broken and doesn't have a timeline for repair: RT 132980. Basically, the target type is not enforced. The docs are updated. My advice is to not use this at all.