Bug #22080
open`Integer(obj, exception: false)` raises when `to_str` doesn't return String
Description
obj = Object.new
def obj.to_str = 1
Integer(obj, exception: false) # can't convert Object to String (Object#to_str gives Integer) (TypeError)
But returning the wrong type from to_int is fine:
obj = Object.new
def obj.to_int = "1"
Integer(obj, exception: false) # nil
Doc says this (https://docs.ruby-lang.org/en/master/Kernel.html#method-i-Integer):
With exception given as false, an exception of any kind is suppressed and nil is returned.
So it looks like it should not raise in both cases. Or more specifically, try to_i next, since that is what happens when to_int returns the wrong type.
Updated by Earlopain (Earlopain _) 22 days ago
- Related to Bug #18998: Kernel#Integer does not convert SimpleDelegator object expectly added
Updated by matz (Yukihiro Matsumoto) 3 days ago
Thank you for the report.
I see the asymmetry, but I think the diagnosis should be the other way around.
The intent of exception: false is to suppress conversion-failure exceptions, such as Integer("abc") raising ArgumentError. It is not meant to suppress contract violations like to_int or to_str returning a value of the wrong type. Those are programming errors in the converter, not failures of the conversion itself. Returning nil for those would silently hide bugs.
Under this principle, the current to_str behavior (raising TypeError) is correct. The current to_int behavior (returning nil) is the one that does not match. I'd like to align by making to_int also raise, and to update the documentation so it no longer says "an exception of any kind".
If changing to_int turns out to break real-world code in practice, we can reconsider and align both to nil (with the documentation rewritten accordingly). But I'd like to try the principled direction first.
Matz.