breed breed - 2 months ago 8
Ruby Question

Ruby puts and the times method on numbers

This code:

puts 1.times { puts 2.times { puts 3.times { puts 4 } } }


Outputs this:

4
4
4
3
4
4
4
3
2
1


I kind of get it, but not really. I guess I'd expect Ruby to output the return value of the
times
method, but it doesn't seem to do that. It prints out the number that
times
is being called on.

Can somebody explain to me what Ruby is doing here?

Answer

I don't really get that output either, so let's dissect it, starting with the innermost expression:

puts 4
# 4           <- this should denote output
#=> nil       <- this should denote return value

It prints 4 and returns nil (puts always returns nil).

Wrapping it in 3.times { ... } prints 4 3 times:

3.times { puts 4 }
# 4
# 4
# 4
#=> 3

But instead of returning nil, it returns 3. This is because times always returns the receiver (i.e. the integer you call times on).

Now let's add another puts:

puts 3.times { puts 4 }
# 4
# 4
# 4
# 3
#=> nil

Same as above, but also prints the result of 3.times { ... }, i.e. 3.

Wrapping everything in 2.times { ... } duplicates the above output:

2.times { puts 3.times { puts 4 } }
# 4
# 4
# 4
# 3
# 4
# 4
# 4
# 3
#=> 2

It also returns 2 instead of nil because of 2.times { ... }.

Adding puts prints that 2:

puts 2.times { puts 3.times { puts 4 } }
# 4
# 4
# 4
# 3
# 4
# 4
# 4
# 3
# 2
#=> nil

Wrapping this in 1.times { ... } produces the same output, but changes the result from nil to 1:

1.times { puts 2.times { puts 3.times { puts 4 } } }
# 4
# 4
# 4
# 3
# 4
# 4
# 4
# 3
# 2
#=> 1

Adding the last puts prints that 1:

puts 1.times { puts 2.times { puts 3.times { puts 4 } } }
# 4
# 4
# 4
# 3
# 4
# 4
# 4
# 3
# 2
# 1
#=> nil
Comments