Bug #21864
closedInconsistencies in type coercion error messages for integers
Description
Some context in https://github.com/ruby/spec/pull/1345, all code snippets are run using Ruby 4.0.1 on a 64bit Linux (Debian) system, unless stated otherwise.
Ruby has some generic type coercion error message. For example:
File.truncate(var, 1)
Depending on the type of var, it can generate error messages like:
no implicit conversion of Integer into String (TypeError)
no implicit conversion of false into String (TypeError)
In general true, false and nil print the string representation of the object, anything else prints the class of the object. One could argue that this is inconsistent, but it's probably better than printing NilClass in the error (something I've recently seen happen in Natalie and TruffleRuby, I would guess JRuby occasionally has this issue as well, but I haven't looked for it. The exact error messages are often missing in the Ruby specs).
The conversion to integer is weird.
File.truncate("/dev/zero", var)
Anything other than nil gets pretty much the same output as before:
no implicit conversion of Symbol into Integer (TypeError)
no implicit conversion of false into Integer (TypeError
But this is where nil has a special path:
no implicit conversion from nil to integer (TypeError)
Now it's usng "from .. to" instead of "of .. into", and integer is written in lower case.
But, this message is not consistent either, based on the size of off_t, where the coercion uses either rb_num2long or rb_num2ll, which have different checks for nil:
// Taken from commit 86dba8cfaeabb3b86df921da24b3243b9ce4ab2a
long
rb_num2long(VALUE val)
{
again:
if (NIL_P(val)) {
rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
}
LONG_LONG
rb_num2ll(VALUE val)
{
if (NIL_P(val)) {
rb_raise(rb_eTypeError, "no implicit conversion from nil");
}
That last one has some internal checks for other types, with more inconsistent error messages:
rb_raise(rb_eTypeError, "no implicit conversion from string");
rb_raise(rb_eTypeError, "no implicit conversion from boolean");
That last one looks like the only error message to mention the term boolean.
IMHO the first message type is the clearest, so I would propose to write every coercion failure in this way:
type = value.nil? || value == true || value == "false" ? value.inspect : value.class
klass = "String" # Or Integer, or ...
"no implicit conversion of #{type} into #{klass}"