0

I'm going through a tutorial on Ruby that explains the neat construction the select method provides. As per that, the three print statements in the following code (filtering out even numbers) should produce an identical output:

numbers = (1..20).to_a
p numbers.select(&:even?)
p numbers.select { |x| x.even? }
p numbers.select do |x| x.even? end

When I run it, though, I get:

[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
#<Enumerator: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]:select> 

Clearly, the third statement is off, even though it's impossible to tell why. It's just the curly braces replaced with the do-end block so it shouldn't change anything.

I'm on Ruby 2.5 so I guess either the tutorial was running some other version and something has changed? Or maybe there's some subtlety here that I'm not able to put my finger on.

ankush981
  • 5,159
  • 8
  • 51
  • 96
  • Check this out: https://stackoverflow.com/questions/5587264/do-end-vs-curly-braces-for-blocks-in-ruby – ellitt Apr 07 '20 at 21:03
  • @ellitt Thanks but I don't see a discussion there about why the return types are different. The accepted answer shows that difference in the output, but no one seems bothered by it! :D – ankush981 Apr 07 '20 at 21:06
  • You'll have to expand the comments on the accepted answer to see that discussion. Also Ursus put it very nicely in the answer below. – ellitt Apr 07 '20 at 21:11
  • @ellitt Ohh. I actually went crazy trying to scan through the stylistic discussion there and gave up. Yes, I saw the answer. Thanks to you too! – ankush981 Apr 07 '20 at 21:17
  • 1
    Asked a couple of times: [Ruby Block Syntax Error](http://StackOverflow.Com/q/6854283/2988), [Code block passed to `each` works with brackets but not with `do`-`end` (ruby)](http://StackOverflow.Com/q/6718340/2988), [Block definition - difference between braces and `do`-`end` ?](http://StackOverflow.Com/q/6179442/2988), [Ruby multiline block without `do` `end`](http://StackOverflow.Com/q/3680097/2988), [Using `do` block vs brackets `{}`](http://StackOverflow.Com/q/2122380/2988), [What is the difference or value of these block coding styles in Ruby?](http://StackOverflow.Com/q/533008/2988), … – Jörg W Mittag Apr 08 '20 at 10:09
  • … [Ruby block and unparenthesized arguments](http://StackOverflow.Com/q/420147/2988), [Why aren't `do`/`end` and `{}` always equivalent?](http://StackOverflow.Com/q/7487664/2988), [Wierd imperfection in Ruby blocks](http://StackOverflow.Com/q/7620804/2988), [Passing block into a method - Ruby](http://StackOverflow.Com/q/10909496/2988), [`instance_eval` block not supplied?](http://StackOverflow.Com/q/12175788/2988), [block syntax difference causes “`LocalJumpError: no block given (yield)`”](http://StackOverflow.Com/q/18623447/2988), … – Jörg W Mittag Apr 08 '20 at 10:09
  • … [`instance_eval` does not work with `do`/`end` block, only with `{}`-blocks](http://StackOverflow.Com/q/21042867/2988), [`Proc` throws error when used with `do` `end`](http://StackOverflow.Com/q/25217274/2988), [Block not called in Ruby](http://StackOverflow.Com/q/29454056/2988), and [Different behaviour of “`do … end`” and “`{ … }`” block in ruby](http://StackOverflow.Com/q/37638152/2988). – Jörg W Mittag Apr 08 '20 at 10:10
  • @JörgWMittag The problem is, it's hard to guess the working that was used to ask similar or exactly same questions. Anyway, thanks for your inputs! :) – ankush981 Apr 18 '20 at 14:00

1 Answers1

2
p numbers.select do |x| x.even? end

is called in this way

p(numbers.select) do |x| x.even? end

The block is passed to p, not to select as you'd expect, p just ignores it

In the second case this doesn't happen because the block with {} has higher precedence than the method call. Instead, block with do-end has lower precedence than the method call.

The second case looks like this instead

p(numbers.select { |x| x.even? })
Ursus
  • 29,643
  • 3
  • 33
  • 50
  • Amazing. Mind-blowing and mind-smashing at the same time! :D I think the use of `p` was somewhat of a contrived example because we'd almost always collect these values in a variable first; but it's always good to know. Thanks! – ankush981 Apr 07 '20 at 21:16