Bug #9397
closed
Lambda#=== raises `ArgumentError` if the lambda accepts 0 args or requires more than 1
Added by myronmarston (Myron Marston) almost 11 years ago.
Updated almost 11 years ago.
Description
Ruby 1.9 introduced ===
on lambdas/procs so that you can put them in case statements. I'm a fan of this, but there's an unfortunate side effect I've run into recently.
If you have a lambda that accepts 0 args (e.g. lambda { }
) or requires more than 1 arg (e.g. lambda { |x, y| }
), calling ===
on it will raise an ArgumentError
. I understand why: lambdas are strict about the number of arguments, and ===
is just an alias of call
now. However, this makes things difficult in a gem when you want to use ===
to match arbitrary objects (since it's the general-purpose protocol ruby provides for that purpose) and there may be lambdas provided by the user. I ran into this in RSpec recently, and my (hacky) solution is to rescue ArgumentError
:
https://github.com/rspec/rspec-support/commit/caf76c5de26ea1ca93f09f1097a0092ee4bf828d
It would be nice not to have to do this, and IMO, ===
on all built-in types should maintain the contract that they can be called with 1 arg and will not raise an error. Consider that ruby's syntax doesn't even allow you to call ===
with 0 or more than 1 argument unless you resort to hacks like send
(e.g. obj.send(:===, x, y, z)
). Given that, I think that ===
on lambdas should return false rather than raising an ArgumentError if the lambda does not support being called with 1 argument.
- Status changed from Open to Rejected
Why lambda
?
You can use proc
for such purpose.
Why lambda?
You can use proc for such purpose.
Users can use rspec's expectations with any kind of object. We can't arbitrarily restrict it and say, "you can't use lambdas". With some new features we're adding, we're leveraging ruby's ===
protocol, and we can't control what kind of objects users pass to us.
Why is it desirable for a built-in type to raise ArgumentError
for ===
rather than returning false?
This seems odd behaviour, given that in normal usage you'd never be able to satisfy the constraint to avoid the ArgumentError, I feel this should return false like a proc would do.
Consider that ruby's syntax doesn't even allow you to call === with 0 or more than 1 argument unless you resort to hacks like send
The syntax allows it, you just need a dot:
-> a, b { a + b }.=== 1,2
-> a, b { a + b }.===(1,2)
-> { 42 }.===
-> { 42 }.===()
Myron Marston wrote:
Why is it desirable for a built-in type to raise ArgumentError
for ===
rather than returning false?
I guess mostly because it would be hard to debug why you never get in a specific clause of the case.
Benoit Daloze wrote:
Consider that ruby's syntax doesn't even allow you to call === with 0 or more than 1 argument unless you resort to hacks like send
The syntax allows it, you just need a dot:
-> a, b { a + b }.=== 1,2
-> a, b { a + b }.===(1,2)
-> { 42 }.===
-> { 42 }.===()
Interesting. You learn something new everyday :).
I'd still put this in the category of hacks like send
, though: the normal, idiomatic way of calling operator methods in ruby is to not use a dot. When was the last time you used a dot to send a message like +
, -
, ==
, ===
, *
, etc?
Also available in: Atom
PDF
Like0
Like0Like0Like0Like0Like0Like0