0

I don't know what is the difference between using 'do..end' and '{}'.

When I use 'do..end' below, it gives me error :368:in `each': no block given (LocalJumpError)

p [50, 17, 1, 22].inject do |acc, el|
    if el < acc
        el
    else
        acc
    end
end

However, When I use '{}' below, it prints '1' the minimum value.

p [50, 17, 1, 22].inject { |acc, el|
    if el < acc
        el
    else
        acc
    end
}

Is it because of the difference of 'precedence'?

Ykim92
  • 1
  • 1
    This is a duplicate of [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 Jul 13 '21 at 19:51
  • 1
    … [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 Jul 13 '21 at 19:51
  • 1
    … [`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), [Different behaviour of “`do … end`” and “`{ … }`” block in ruby](http://StackOverflow.Com/q/37638152/2988), and [Ruby syntax for passing block](https://stackoverflow.com/q/61749537/2988). – Jörg W Mittag Jul 13 '21 at 19:52

1 Answers1

2

The problem is purely in the use of p and, like you say, the order of precedence - because you're relying on ruby to define precedence based on whitespace, instead of declaring it explicitly with brackets.

The ruby interpreter reads it like this:

p([50, 17, 1, 22].inject) do
  # ...
end

vs

p([50, 17, 1, 22].inject { ... })

... In other words, when using do ... end syntax, the block is getting passed to the p method, not the inject method!

Therefore if you wish to both keep the do ... end block syntax and print the result, you must either add brackets like:

p([50, 17, 1, 22].inject do |acc, el|
    if el < acc
        el
    else
        acc
    end
end)

Or, assign a temporary variable like:

x = [50, 17, 1, 22].inject do |acc, el|
    if el < acc
        el
    else
        acc
    end
end

p x
Tom Lord
  • 27,404
  • 4
  • 50
  • 77
  • As an addendum to this, when it comes to parsing of blocks there is another notable difference between `do...end` and `{}`. `[1, 2, 3].inject 0 { |a, b| a + b }` will not work as it requires parentheses, but `[1, 2, 3].inject 0 do |a, b| a + b end` will work as expected. – Chris Jul 13 '21 at 19:05
  • Also as an addendum, you could write that block with a ternary statement: `el < acc ? el : acc`, or even write it as `[el, acc].min`. Either way, it now fits neatly onto one line, meaning you don't really need `do ... end` syntax here. – Tom Lord Jul 13 '21 at 19:17
  • Learning often means doing things that be pointless if you already knew more, but are hopefully ultimately enlightening. :) – Chris Jul 13 '21 at 19:25