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) 4 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) 3 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) 3 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]