0

Found an interesting quirk in the ruby interpreter - at least in MRI 2.4.2.

As far as I can tell, each of the below code snippets should print '123'. If I try to print the result of reduce directly, I get NoMethodError: undefined method '' for 1:Integer (or whatever type the array contains) But if I first save the result and then print it, it works fine..

So, this code is broken:

puts [1,2,3].reduce('') do |memo, num|
  memo + num.to_s
end

And this code works:

temp = [1,2,3].reduce('') do |memo, num|
  memo + num.to_s
end
puts temp

These should work exactly the same, right? Should this be filed as a bug? Am I just missing something fundamental here?

I'd think it should at least show which method is trying to be called. Can't find anything in google about an undefined method without a method name...

iCodeSometime
  • 1,444
  • 15
  • 30
  • Does the second code snippet work? I am getting `nil`, not sure if that is what you are expecting. – chevybow May 03 '18 at 15:03
  • Yes. temp is successfully set to '123', and puts prints it normally (which also returns nil, is that what you're seeing?) Updated question for clarity – iCodeSometime May 03 '18 at 15:07
  • 2
    This has been asked numerous times already. You are passing the block to `puts`, not to `inject`. – Jörg W Mittag May 03 '18 at 15:29

1 Answers1

1

You need parenthesis on the puts call. This works:

puts([1,2,3].reduce('') do |memo, num|
  memo + num.to_s
end)

Normally you can avoid parenthesis, but sometimes the parser will find ambiguities and will just raise an error, like in your first case.

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Simone
  • 20,302
  • 14
  • 79
  • 103
  • Thanks! I guess i can see how it would be ambiguous if puts accepted a block, and reduce didn't require one in this case. Just to be clear, generally, parens are always needed if there should be a block inside the function call? – iCodeSometime May 03 '18 at 15:23
  • @kennycoc I think so, yeah. – Simone May 04 '18 at 09:05