Bug #21563
closedMisleading error message when `to_proc` does not return a Proc in an Object used as a &block argument
Description
When a class implements #to_proc
it should always return a Proc. Nonetheless bugs are possible, and when an implementation returns something else, and is used as a block argument to a method, you get an error that claims that the argument type is the implementing class rather than the type that was returned from to_proc
.
Reproduction
class SayHi
def call = "hi"
def to_proc = "obviously not a proc"
end
def callablock(&block) = block.call
callablock &SayHi.new # wrong argument type SayHi (expected Proc) (TypeError)
In real-world code it may not be this obvious that to_proc
is returning the wrong type, and so I would expect the error would report the type of object returned by to_proc
so that you have a more-direct path to understanding the misbehavior. In this case I would expect:
wrong argument type String (expected Proc)
Or maybe something more-descriptive as an error message, but I don't have a concrete suggestion for that.
Updated by jeremyevans0 (Jeremy Evans) 27 days ago
If we want to change the behavior in this case, we should report both the actual argument and the return value of to_proc
. That's what we do for *a
where a.to_a
returns non-Array and for **h
where h.to_hash
returns non-Hash):
A = Class.new
a = A.new
def a.to_a = 1
def a.to_hash = 1
p(*a) # can't convert A to Array (A#to_a gives Integer) (TypeError)
p(**a) # can't convert A to Hash (A#to_hash gives Integer) (TypeError)
def a.to_proc = 1
p(&a)
# currently: wrong argument type A (expected Proc) (TypeError)
# preferable: can't convert A to Proc (A#to_proc gives Integer) (TypeError)
Updated by jeremyevans0 (Jeremy Evans) 27 days ago
I submitted a PR to make the error messages for & consistent with */**: https://github.com/ruby/ruby/pull/14463
Updated by jeremyevans (Jeremy Evans) 26 days ago
- Status changed from Open to Closed
Applied in changeset git|953e1ef99283d8563ff655ee6b8fcd681af79c1c.
Make invalid & operator type error message consistent with /*
If #to_proc is defined, this uses the following error message format,
matching the error message format used for * when to_a returns non-Array
and for ** when to_hash returns non-Hash:
can't convert ClassName to Proc (ClassName#to_proc gives OtherClassName)
If #to_proc is not defined, this uses the following error message format,
matching the error message format used when ** is called on a non-Hash
not implementing to_hash.
no implicit conversion of ClassName into Proc
There isn't a similar error for * when called on a non-Array not
implementing to_a, as Ruby does not raise for that case.
Fixes [Bug #21563]