"+1" gives me different result than "+ 1" in ruby?

Viewed 85
[6] pry(main)> [1,2,3].min +1
=> [1]
[7] pry(main)> [1,2,3].min + 1
=> 2

I'm blown away. it must be something to do with the min function i suppose? because max has the same issue but not sum

2 Answers

Whitespace matters in Ruby, at least sometimes.

If you say x + 1 then Ruby interprets the + as the binary addition operator so it is seen as a method call like x.+(1).

If you say x +1 then Ruby interprets the + as the unary plus operator (AKA #+@) and the space as a method call so the expression as a whole is seen as x(+1) or more explicitly x(1.+@()).

An expression like x ・ y (for some operator ・) can be interpreted in different ways as method-calling-parentheses are (sometimes) optional. It can be seen as x(・ y) or x() ・ y and Ruby chooses the latter. When there is no second space (i.e. x ・y) then Ruby sees it as x(・y). Things are further complicated because x could be a local variable or a method call. Optional parentheses and whitespace introduces some ambiguity for humans but not for Ruby.

So adding missing/optional parentheses to [1,2,3].min +1 gives us:

[1,2,3].min(+1)

and you're calling Array#min with an argument of 1 and that will:

With Integer argument n and no block, returns a new Array with at most n elements, in ascending order per method <=>:

Hence the [1] result.

Adding parentheses to [1,2,3].min + 1 gives us:

[1,2,3].min() + 1

which is 1 + 1 or 2.

Ruby's Array::min takes an optional argument n, which returns the smallest n items as an array. When you place a space to the left of the + but no space to the right, it's interpreting that to mean you want a unary positive 1 as the optional argument so you get [1]. Having spaces on both sides of the + or neither side will be parsed as a desire to add one to the result of min.

[10,11,12].min       # => 10
[10,11,12].min(+1)   # => [10]
[10,11,12].min(+2)   # => [10, 11]
[10,11,12].min +2    # => [10, 11]  since parentheses are often optional in Ruby
[10,11,12].min+1     # => 11  without spaces, interpreted as addition rather than unary +
[10,11,12].min + 1   # => 11  spaces on both sides, also interpreted as addition
Related