Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert a Str to an Int only when it represents an integer?

Tags:

signature

raku

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.

like image 247
brian d foy Avatar asked Mar 13 '18 17:03

brian d foy


People also ask

Which method is used to convert a number in string to an integer?

We can use the parseInt(String str) method of the Integer wrapper class for converting a String value to an integer value.

Can you convert strings to integers in Python?

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.


2 Answers

One possible signature would be

Numeric() $ where Int

or, restricting to strings,

Numeric(Str:D) $ where Int
like image 121
Christoph Avatar answered Sep 21 '22 22:09

Christoph


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}" }
like image 34
Brad Gilbert Avatar answered Sep 20 '22 22:09

Brad Gilbert