[ruby-core:124687] [Ruby Bug#21864] Inconsistencies in type coercion error messages for integers
Issue #21864 has been reported by herwin (Herwin W). ---------------------------------------- Bug #21864: Inconsistencies in type coercion error messages for integers https://bugs.ruby-lang.org/issues/21864 * Author: herwin (Herwin W) * Status: Open * 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 * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- 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: ```ruby 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. ```ruby 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`: ```c // 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: ```c 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: ```ruby type = value.nil? || value == true || value == "false" ? value.inspect : value.class klass = "String" # Or Integer, or ... "no implicit conversion of #{type} into #{klass}" ``` -- https://bugs.ruby-lang.org/
Issue #21864 has been updated by Eregon (Benoit Daloze). +1, I think all messages should be consistent with what `convert_type_with_id` uses: https://github.com/ruby/ruby/blob/86dba8cfaeabb3b86df921da24b3243b9ce4ab2a/o... To give a concrete example here, a specific problem is it's weird to specify the expected error message since the typedef of `off_t` depends on the platform and so `File.truncate(filename, nil)` gives: `no implicit conversion from nil to integer` on Linux (where `off_t`=`long`) but `no implicit conversion from nil` on macOS (where `off_t`=`long long`). ---------------------------------------- Bug #21864: Inconsistencies in type coercion error messages for integers https://bugs.ruby-lang.org/issues/21864#change-116283 * Author: herwin (Herwin W) * Status: Open * 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 * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- 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: ```ruby 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. ```ruby 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`: ```c // 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: ```c 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: ```ruby type = value.nil? || value == true || value == "false" ? value.inspect : value.class klass = "String" # Or Integer, or ... "no implicit conversion of #{type} into #{klass}" ``` -- https://bugs.ruby-lang.org/
Issue #21864 has been updated by byroot (Jean Boussier). I'm working a a small refactor: https://github.com/ruby/ruby/pull/16078 I have to battle a bit with some test assertions, but it's pretty simple. ---------------------------------------- Bug #21864: Inconsistencies in type coercion error messages for integers https://bugs.ruby-lang.org/issues/21864#change-116285 * Author: herwin (Herwin W) * Status: Open * 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 * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- 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: ```ruby 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. ```ruby 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`: ```c // 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: ```c 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: ```ruby type = value.nil? || value == true || value == "false" ? value.inspect : value.class klass = "String" # Or Integer, or ... "no implicit conversion of #{type} into #{klass}" ``` -- https://bugs.ruby-lang.org/
participants (3)
-
byroot (Jean Boussier) -
Eregon (Benoit Daloze) -
herwin (Herwin W)