Why does `1i.to_i` raise `RangeError` instead of `NoMethodError`?

  • A+

NoMethoError is raised by to_i simply because the class doesn't have the method:

[].to_i # >> NoMethodError (undefined method `to_i' for []:Array) 

Surely enough, 1i has the method to_i and to_f, so it responds to them. But in reality this looks very tricky.

1i.respond_to?(:to_i) # => true 1i.to_i # >> RangeError (can't convert 0+1i into Integer) 

From where does the Range class come in here?


Surely enough, 1i has the method .to_i and .to_f so it responds to them. But in reality this looks very tricky!

Yes, it responds to them. And when you invoke to_i on the complex literal 1i, that method throws a RangeError. That has nothing to do with the Range class; it is telling you that although 1i has a to_i method from class Complex, its specific value is not one for which a meaningful result can be obtained.

Or to put it another way, that's what Complex::to_i does when invoked on an object whose imaginary part is nonzero or even inexact:

to_i → integer

Returns the value as an integer if possible (the imaginary part should be exactly zero).

Complex(1, 0).to_i    #=> 1 Complex(1, 0.0).to_i  # RangeError Complex(1, 2).to_i    # RangeError 

A RangeError communicates roughly that an argument is outside the range of the function to which it was provided, i.e. in the mathematical sense of "range". Complex is a bit unusual in applying that sense of "range" to the target object, as opposed to a method argument, but it nevertheless makes sense.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: