Project

General

Profile

Actions

Bug #9397

closed

Lambda#=== raises `ArgumentError` if the lambda accepts 0 args or requires more than 1

Added by myronmarston (Myron Marston) over 10 years ago. Updated over 10 years ago.

Status:
Rejected
Assignee:
-
Target version:
-
[ruby-core:<unknown>]

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.

Actions #1

Updated by nobu (Nobuyoshi Nakada) over 10 years ago

  • Status changed from Open to Rejected

Why lambda?
You can use proc for such purpose.

Actions #2

Updated by myronmarston (Myron Marston) over 10 years ago

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?

Actions #3

Updated by JonRowe (Jon Rowe) over 10 years ago

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.

Actions #4

Updated by Eregon (Benoit Daloze) over 10 years ago

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 }.===()

Actions #5

Updated by Eregon (Benoit Daloze) over 10 years ago

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.

Actions #6

Updated by myronmarston (Myron Marston) over 10 years ago

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?

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0