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.
We can use the parseInt(String str) method of the Integer wrapper class for converting a String value to an integer value.
To convert, or cast, a string to an integer in Python, you use the int() built-in function. The function takes in as a parameter the initial string you want to convert, and returns the integer equivalent of the value you passed.
One possible signature would be
Numeric() $ where Int
or, restricting to strings,
Numeric(Str:D) $ where Int
The way Int:D(Any)
works in Rakudo is by creating a multi candidate that accepts Any
, converts it to an Int, and uses the result to call your original subroutine.
If you instead do that yourself, you can have more control over how it works.
proto sub foo ( Int:D() $n ) {*}
multi sub foo ( Any:D $n ) {
my $i = try $n.Numeric.narrow;
if $i ~~ Int:D {
samewith $i
} else {
X::TypeCheck::Binding::Parameter.new(
# there are more arguments that should be added here
got => $n,
expected => Int:D(),
).throw
}
}
multi sub foo ( Int:D $n ) { put "Got <$n> of type {$n.^name}" }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With