Project

General

Profile

Actions

Bug #21864

closed

Inconsistencies in type coercion error messages for integers

Bug #21864: Inconsistencies in type coercion error messages for integers

Added by herwin (Herwin W) 2 days ago. Updated about 6 hours ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [x86_64-linux], but consisten since at least Ruby 3.2, haven't checked older releases
[ruby-core:124687]

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}"
Actions

Also available in: PDF Atom