No exceptions from String#to_i


(HAL 9000) #1

I’ve been bitten by this before… maybe
it is a feature, but I’m not sure of the
reasoning.

I wrote a line like this:

num = gets.chomp.to_i rescue max

thinking that a simple carriage return
would assign max to num.

But of course, “”.to_i does not give us
an error; it simply returns zero (as does
"foo".to_i or any other such string).

What is the reason for this? My instinct
is that an exception should result.

I know it’s been discussed before, but I
can’t find it now.

Thanks,
Hal Fulton


(ts) #2

I know it's been discussed before, but I
can't find it now.

use #Integer if you want an error

pigeon% ruby -e 'Integer("")'
-e:1:in `Integer': invalid value for Integer: "" (ArgumentError)
        from -e:1
pigeon%

Guy Decoux


(HAL 9000) #3

Ah, thank you, I remember that now.

Which raises the question: Why is this
"non-OO"? Why not str.integer (for instance)
instead of Integer(str)? Is it just to make
it more universally available (i.e., to
different data types, Integer(non_str_obj))?

And why is Integer capitalized? I know of
only four methods in the entire Ruby core
that start with capital letters.

I sound like a five year old, do I not?
Always asking why… :slight_smile:

Thanks,
Hal Fulton

···

----- Original Message -----
From: “ts” decoux@moulon.inra.fr
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Cc: ruby-talk@ruby-lang.org
Sent: Monday, June 24, 2002 6:40 AM
Subject: Re: No exceptions from String#to_i

I know it’s been discussed before, but I
can’t find it now.

use #Integer if you want an error

pigeon% ruby -e ‘Integer("")’
-e:1:in `Integer’: invalid value for Integer: “” (ArgumentError)
from -e:1
pigeon%


(Nikodemus Siivola) #4

More whys and wherefore’s…

I find this mildly strange:

Integer(’’) #-> exception

Integer(nil) == 0
Integer(false) #-> exception

Integer(:foo) == 14145
Integer(‘foo’) #-> exception

Is this ‘jus the way it is’, or is there a reason? I suppose symbols get
hashed, but then why not apply the same logic to strings as well?

Also, since nil and false are the only non-true values, I would expect
them to be treated the same in such a case.

Further strangeness:

Why ?

Array(foo) == foo.to_a
String(foo) == foo.to_s
Integer(foo) != foo.to_i
Float(foo) != foo.to_f

– Nikodemus

···

On Mon, 24 Jun 2002, ts wrote:

use #Integer if you want an error


(ts) #5

Which raises the question: Why is this
"non-OO"? Why not str.integer (for instance)
instead of Integer(str)? Is it just to make
it more universally available (i.e., to
different data types, Integer(non_str_obj))?

Well, you can write

pigeon% ruby -e 'p Integer(12.4)'
12
pigeon%

And why is Integer capitalized? I know of
only four methods in the entire Ruby core
that start with capital letters.

and they do the same thing (a conversion) :slight_smile:

Guy Decoux


(ts) #6

Integer(nil) == 0

  nil.to_i is defined

Integer(false) #-> exception

false.to_i is not defined

Array(foo) == foo.to_a

  Well, first ruby look if #to_ary exist and call it otherwise it try to
  call #to_a

Integer(foo) != foo.to_i
Float(foo) != foo.to_f

it depend of foo

pigeon% ruby
class A
   def to_f
      12.0
   end
end

p Float(A.new)
^D
12.0
pigeon%

Guy Decoux


(Yukihiro Matsumoto) #7

Hi,

I find this mildly strange:

Integer(’’) #-> exception

Integer(nil) == 0
Integer(false) #-> exception

Integer(:foo) == 14145
Integer(‘foo’) #-> exception

Is this ‘jus the way it is’, or is there a reason? I suppose symbols get
hashed, but then why not apply the same logic to strings as well?

Something that isn’t naturally convertable to an integer causes
error. Symbols and nil are exception from historical reason, but
maybe they will be error in the future.

Why ?

Array(foo) == foo.to_a
String(foo) == foo.to_s
Integer(foo) != foo.to_i
Float(foo) != foo.to_f

Functional style methods are more strict than their OO style
counterpart in general.

						matz.
···

In message “Re: No exceptions from String#to_i” on 02/06/24, Nikodemus Siivola tsiivola@cc.hut.fi writes:


(Nikodemus Siivola) #8

Thank you for the explanation of the mechanism. I am also wondering on the
rationale for differences between then four Kernel methods and various
to_X methods. The same applies to the difference between to_str/to_s and
to_ary/to_a. Different tools for different jobs, but as to what those jobs
might be is a bit murky for me.

Can someone enlighten me?

– Nikodemus

···

On Mon, 24 Jun 2002, ts wrote:

nil.to_i is defined


(Florian Frank) #9

There are exceptions to this rule:

Float(nil) => 0.0

object.c:
case T_NIL:
return rb_float_new(0.0);

But nil.to_f throws an exception because it isn’t defined.

Someone posted an RCR on Ruby Garden concerning this issue:
http://www.rubygarden.org/article.php?sid=241

This small patch adds the to_f-method to NilClass:

Index: object.c

···

Am 2002-06-24 21:23:58 +0900 schrieb ts:

Integer(nil) == 0

nil.to_i is defined

Integer(false) #-> exception

false.to_i is not defined

Array(foo) == foo.to_a

Well, first ruby look if #to_ary exist and call it otherwise it try to
call #to_a

Integer(foo) != foo.to_i
Float(foo) != foo.to_f

it depend of foo

===================================================================
RCS file: /src/ruby/object.c,v
retrieving revision 1.79
diff -u -r1.79 object.c
— object.c 2002/05/21 05:39:19 1.79
+++ object.c 2002/06/24 14:49:46
@@ -338,6 +338,13 @@
}

static VALUE
+nil_to_f(obj)

  • VALUE obj;
    +{
  • return rb_float_new(0.0);
    

+}
+
+static VALUE
nil_to_s(obj)
VALUE obj;
{
@@ -1072,9 +1079,6 @@
case T_STRING:
return rb_float_new(rb_str_to_dbl(val, Qtrue));

  •  case T_NIL:
    
  •   return rb_float_new(0.0);
    
  •  default:
      return rb_convert_type(val, T_FLOAT, "Float", "to_f");
    

    }
    @@ -1282,6 +1286,7 @@

    rb_cNilClass = rb_define_class(“NilClass”, rb_cObject);
    rb_define_method(rb_cNilClass, “to_i”, nil_to_i, 0);

  • rb_define_method(rb_cNilClass, “to_f”, nil_to_f, 0);
    rb_define_method(rb_cNilClass, “to_s”, nil_to_s, 0);
    rb_define_method(rb_cNilClass, “to_a”, nil_to_a, 0);
    rb_define_method(rb_cNilClass, “inspect”, nil_inspect, 0);

I don’t know if this breaks any existing code.


To assert that the earth revolves around the sun is as erroneous as to claim
that Jesus was not born of a virgin.
– Cardinal Bellarmine, “The trial of Galileo”, 1615


(Paul Brannan) #10

Unfortunately, it’s not possible to do this with user-defined data
types. If I have a String-like class with a to_i method that I want to
return 0 on error, then I can do that, but then Integer() will also
return 0 on error. If I want Integer() to raise an exception on error,
then to_i must also raise an exception on error.

It’s not good to have a standard library feature that user libraries
cannot emulate.

Paul

···

On Tue, Jun 25, 2002 at 12:27:03AM +0900, Yukihiro Matsumoto wrote:

Functional style methods are more strict than their OO style
counterpart in general.


(ts) #11

Thank you for the explanation of the mechanism. I am also wondering on the
_rationale_ for differences between then four Kernel methods and various
to_X methods.

Look at [ruby-talk:1007]

   http://www.ruby-talk.org/1007

             The same applies to the difference between to_str/to_s and
to_ary/to_a. Different tools for different jobs, but as to what those jobs
might be is a bit murky for me.

[ruby-talk:23653]

Guy Decoux


(Nikodemus Siivola) #12

Agreed. Could functional style call to_ary, to_int, to_str and to_flt
instead?

– Nikodemus

···

On Tue, 25 Jun 2002, Paul Brannan wrote:

It’s not good to have a standard library feature that user libraries
cannot emulate.


(Yukihiro Matsumoto) #13

Hi,

···

In message “Re: No exceptions from String#to_i” on 02/06/25, Paul Brannan pbrannan@atdesk.com writes:

Unfortunately, it’s not possible to do this with user-defined data
types. If I have a String-like class with a to_i method that I want to
return 0 on error, then I can do that, but then Integer() will also
return 0 on error. If I want Integer() to raise an exception on error,
then to_i must also raise an exception on error.

It’s not good to have a standard library feature that user libraries
cannot emulate.

How about Array(), Integer(), String() use to_ary, to_int, to_str
respectively [ruby-talk:43014], and Float() raises error if to_f
return NaN?

						matz.

(Martin S. Weber) #14

Couldn’t we get type-bound generic functions instead of message passing style calls ?
blink

-Martin (not 'serious)

···

On Tue, Jun 25, 2002 at 06:36:59AM +0900, Nikodemus Siivola wrote:

On Tue, 25 Jun 2002, Paul Brannan wrote:

It’s not good to have a standard library feature that user libraries
cannot emulate.

Agreed. Could functional style call to_ary, to_int, to_str and to_flt
instead?


(Yukihiro Matsumoto) #15

Hi,

···

In message “Re: No exceptions from String#to_i” on 02/06/25, Nikodemus Siivola tsiivola@cc.hut.fi writes:

It’s not good to have a standard library feature that user libraries
cannot emulate.

Agreed. Could functional style call to_ary, to_int, to_str and to_flt
instead?

It seems a good idea. Let me think about it.
Will you submit RCR just for a record?

						matz.

(Nikodemus Siivola) #16

Sounds decent, but isn’t NaN technically a float? Also, since code that
handles floats should also be able to handle NaNs, it might be simpler to
just pass it along. Having it raise an error means that in some cases
there will have to be handling for both the exception from Float() and
handling for NaNs in general.

Also, why handle Float() differently? If because there is no to_flt as of
yet, then that holds for to_int as well… :wink:

– Nikodemus

···

On Tue, 25 Jun 2002, Yukihiro Matsumoto wrote:

respectively [ruby-talk:43014], and Float() raises error if to_f
return NaN?


(Nikodemus Siivola) #17

Done.

Since it seems that core Integer, Float, String and Array are sort
of core classes in Ruby, it might also be nice to redefine Object’s
to_s, to_i, to_f and to_a to call the long form if it exists. This way the
long form would give the short one for free.

Something like:

class Object
def to_s
if respond_to? :to_str
to_str
else
inspect
end
end
def to_a
if respond_to? :to_ary
to_ary
else
[self]
end
end
def method_missing( message, *args )
case message
when :to_i then to_int if respond_to? :to_int
when :to_f then to_flt if respond_to? :to_flt
end
end

– Nikodemus

···

On Tue, 25 Jun 2002, Yukihiro Matsumoto wrote:

It seems a good idea. Let me think about it.
Will you submit RCR just for a record?


(Yukihiro Matsumoto) #18

Hi,

respectively [ruby-talk:43014], and Float() raises error if to_f
return NaN?

Sounds decent, but isn’t NaN technically a float? Also, since code that
handles floats should also be able to handle NaNs, it might be simpler to
just pass it along. Having it raise an error means that in some cases
there will have to be handling for both the exception from Float() and
handling for NaNs in general.

Good point. Hmm…

Also, why handle Float() differently? If because there is no to_flt as of
yet, then that holds for to_int as well… :wink:

Mostly because I didn’t see cases “to_flt” is useful.

						matz.
···

In message “Re: No exceptions from String#to_i” on 02/06/25, Nikodemus Siivola tsiivola@cc.hut.fi writes:


(Yukihiro Matsumoto) #19

Hi,

···

In message “Re: No exceptions from String#to_i” on 02/06/25, Nikodemus Siivola tsiivola@cc.hut.fi writes:

Since it seems that core Integer, Float, String and Array are sort
of core classes in Ruby, it might also be nice to redefine Object’s
to_s, to_i, to_f and to_a to call the long form if it exists. This way the
long form would give the short one for free.

I don’t think it’s needed. It slows down the performance.

						matz.