Search code examples
rubylambdadetectenumerableproc

Why does Enumerable#detect need a Proc/lambda?


Enumerable#detect returns the first value of an array where the block evaluates to true. It has an optional argument that needs to respond to call and is invoked in this case, returning its value. So,

(1..10).detect(lambda{ "none" }){|i| i == 11} #=> "none"

Why do we need the lambda? Why don't we just pass the default value itself, since (in my tests) the lambda can't have any parameters anyway? Like this:

(1..10).detect("none"){|i| i == 11} #=> "none"

Solution

  • As with all things in Ruby, the "principle of least surprise" applies. Which is not to say "least surprise for you" of course. Matz is quite candid about what it actually means:

    Everyone has an individual background. Someone may come from Python, someone else may come from Perl, and they may be surprised by different aspects of the language. Then they come up to me and say, 'I was surprised by this feature of the language, so Ruby violates the principle of least surprise.' Wait. Wait. The principle of least surprise is not for you only. The principle of least surprise means principle of least my surprise. And it means the principle of least surprise after you learn Ruby very well. For example, I was a C++ programmer before I started designing Ruby. I programmed in C++ exclusively for two or three years. And after two years of C++ programming, it still surprises me.

    So, the rational here is really anyone's guess.

    One possibility is that it allows for or is consistent with use-cases where you want to conditionally run something expensive:

    arr.detect(lambda { do_something_expensive }) { |i| is_i_ok? i }
    

    Or as hinted by @majioa, perhaps to pass a method:

    arr.detect(method(:some_method)) { |i| is_i_ok? i }