String to int: ruby documentation?

Hi,

In trying to convert a string to an integer, I found this passage in the
ruby documentation:
http://dev.rubycentral.com/ref/


str.to_i → anInteger

Returns the result of interpreting leading characters in str as a
decimal integer. Extraneous characters past the end of a valid number
are ignored. If there is not a valid number at the start of str, 0 is
returned. The method never raises an exception.

That description seems complete. It talks about edge cases, and what
happens, and that the method doesn’t throw an exception. Then I found
this passage:


Integer( arg ) → anInteger

Converts arg to a Fixnum or Bignum. Numeric types are converted directly
(with floating point numbers being truncated). If arg is a String,
leading radix indicators (0, 0b, and 0x) are honored. This behavior is
different from that of String#to_i.

In that description, there is no mention of exceptions that can be
thrown, but when I try the Integer() method, this is the output:

irb(main):002:0> Integer(“10”)
=> 10
irb(main):003:0> Integer(“10abc”)
ArgumentError: invalid value for Integer: “10abc”
from (irb):3:in Integer' from (irb):3 irb(main):004:0> Integer("hello") ArgumentError: invalid value for Integer: "hello" from (irb):4:in Integer’
from (irb):4
irb(main):005:0>

So, it seems pretty clear that the Integer() method can throw an
ArgumentError exception, and I’m wondering why the docs don’t mention
what exceptions Integer() throws? Is that typical of the docs? If it
doesn’t say “no exceptions are thrown”, should I assume it can throw
some as yet unidentified exception?

irb(main):036:0> Class.constants.map { |c| eval©.new rescue
nil }.compact.map { |s| Integer(s) rescue $! }.select { |c| c.is_a?
(Exception) }.map { |c| c.class }.uniq
=> [TypeError, ArgumentError, NoMethodError]

Looks like it could TypeError and NoMethodError as well…

Eden Li wrote:

irb(main):036:0> Class.constants.map { |c| eval©.new rescue
nil }.compact.map { |s| Integer(s) rescue $! }.select { |c| c.is_a?
(Exception) }.map { |c| c.class }.uniq
=> [TypeError, ArgumentError, NoMethodError]

Looks like it could TypeError and NoMethodError as well…

So the docs don’t “document” which exceptions can be thrown by a method?

On Mar 11, 2007, at 6:39 PM, 7stud 7stud wrote:

Eden Li wrote:

irb(main):036:0> Class.constants.map { |c| eval(c).new rescue
nil }.compact.map { |s| Integer(s) rescue $! }.select { |c| c.is_a?
(Exception) }.map { |c| c.class }.uniq
=> [TypeError, ArgumentError, NoMethodError]

Looks like it could TypeError and NoMethodError as well…

So the docs don’t “document” which exceptions can be thrown by a
method?

The documentation isn’t perfect. There is information about
contributing
to Ruby documentation at www.ruby-doc.org.

It has been my observation that the Ruby style is to avoid the use
of exceptions as part of the expected behavior of a method. What I mean
is that, in general, if you provide arguments to a method that meet the
method’s pre-conditions then you will get back a result with no
exception
being raised. If you provide arguments that don’t meet the
pre-conditions of a method, well then you may or may not get an
exception
but it is really your problem in either case because you violated the
pre-condition and all bets are off.

Test driven development really puts the burden on the caller to provide
the correct arguments and methods are often written with that explicit
expectation, which tends to reduce the amount of argument checking that
is done in methods.

When exceptions are explicitly part of the behavior of a method then I,
of course, think their use should be documented.

I’d be interested in other perspectives on best practices with respect
to exceptions and argument checking in API/class design.

Gary W.

I think this depends somewhat on your definition of an argument.

If I do “0101110”.to_i(2), then clearly 2 is an argument. But is
“0101110”? Technically, no, it is the receiver. In Ruby’s duck typed
world where multiple, same named methods do different things depending
on class, then it kindof is an argument.

Dan

The docs wrote:

Integer( arg ) -> anInteger
…If arg is a String

Gary W. wrote:

being raised. If you provide arguments that don’t meet the
pre-conditions of a method, well then you may or may not get an
exception
but it is really your problem in either case because you violated the
pre-condition and all bets are off.

I gave Integer() a string and it threw an exception.

On Mar 11, 2007, at 8:19 PM, Daniel F. wrote:

I think this depends somewhat on your definition of an argument.

If I do “0101110”.to_i(2), then clearly 2 is an argument. But is
“0101110”? Technically, no, it is the receiver. In Ruby’s duck
typed world where multiple, same named methods do different things
depending on class, then it kindof is an argument.

But the current state of an object can certainly be part of the pre-
condition for a method. Pre-conditions aren’t entirely about the
arguments to a method.

Gary W.

Alle lunedì 12 marzo 2007, 7stud 7stud ha scritto:

I gave Integer() a string and it threw an exception.

A quick look at the documentation has lead me to the following
considerations:

There are some places where documentation about exceptions raised is
truly
missing (examples: File.read => LoadError if file doesn’t exist;
File.write
=> SystemCallError if file isn’t open for writing, and, of course
Integer()).
These methods, in my opinion, need to be better documented.

Some situations are implicitly assumed to throw exceptions:

  • passing a method an argument of a type different from the one required
    (for
    example, a string to Fixnum#to_s), raises a TypeError exception
  • passing a method an argument which is of the correct type, but which
    doesn’t
    fulfill al the prerequisites (for instance, passing an integer greater
    than
    36 to Fixnum#to_s), raises an ArgumentError exception
  • a method which should do some parsing (for instance Regexp.new or
    YAML.load)
    raises an exception if the string doesn’t contain valid code. The kind
    of
    exception varies, though (Regexp.new raises a RegexpError while
    YAML.load
    raises ArgumentError)

Stefano

On Mar 11, 2007, at 11:20 PM, 7stud 7stud wrote:

I gave Integer() a string and it threw an exception.

I muddled up a specific response to you about Integer with some
more general observations about exceptions and Ruby. Sorry I wasn’t
clear:

  1. Ruby documentation isn’t perfect. You found a problem.
  2. There are methods (i.e. Integer()) where exceptions are part
    of the expected behavior of the method and they should be
    documented. If they aren’t, that is a bug not a feature.
  3. Most Ruby methods don’t say anything about exceptions because
    exceptions are not part of the API of most Ruby methods. There
    is an overall assumption that if you call a method without meeting
    the pre-conditions then the behavior (including the raising of
    exceptions) is undefined.
  4. Pre-conditions should be clearly described by the documentation.

Gary W.

Gary W. wrote:

On Mar 11, 2007, at 11:20 PM, 7stud 7stud wrote:

I gave Integer() a string and it threw an exception.

I muddled up a specific response to you about Integer with some
more general observations about exceptions and Ruby. Sorry I wasn’t
clear:

  1. Ruby documentation isn’t perfect. You found a problem.
  2. There are methods (i.e. Integer()) where exceptions are part
    of the expected behavior of the method and they should be
    documented. If they aren’t, that is a bug not a feature.
  3. Most Ruby methods don’t say anything about exceptions because
    exceptions are not part of the API of most Ruby methods. There
    is an overall assumption that if you call a method without meeting
    the pre-conditions then the behavior (including the raising of
    exceptions) is undefined.
  4. Pre-conditions should be clearly described by the documentation.

Gary W.

Ok. I was all set to buy the pickaxe book, but then I noticed that
missing documentation, so I decided to look for alternatives. I looked
in “The Ruby Way”, and it mentions that Integer() throws an exception
when the string is not of the right format in a section titled something
like “Turning strings into numbers”. So it looks like those books would
be good companion texts.