How to convert a string to Int only when it represents an integer?

In Perl 6, you can specify a type to which a type can be bound. If you need Int , but get something else that can be converted to Int . This is convenient if you do not need separate candidates for Int and Str , where the string represents an integer value.

But it looks like the conversion is a bit aggressive, because the conversion not only changes the type, but also wants to change the data. This is partly the problem of merging changing types and the expected operation to truncate a number to an integer. Conceptually, these are different ideas, but they are intertwined in Str.Int (in fact, a side transition sandwich on 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 restrict this to Str no 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 that seem 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 may possibly come up with some subsets, but that is no more satisfactory. So the trick is, can I force this without changing the meaning (even if it changes the view)?


It turns out that this function is broken and does not have a timeline for repair: RT 132980 . In principle, the target type does not apply. Documents are updated. My advice is not to use this at all.

+7
perl6 signature
source share
2 answers

The Int:D(Any) method works in Rakudo, creating a multi-level candidate that accepts Any , converts it to Int, and uses the result to call your original subroutine.

If you do it 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}" } 
+6
source share

One possible signature is

 Numeric() $ where Int 

or, limiting the lines,

 Numeric(Str:D) $ where Int 
+8
source share

All Articles