Question

I'm going through a Ruby tutorial, and learned that the code

puts 'start'
puts
puts 'end'

will output three lines, but the following code

puts 'start'
puts []
puts 'end'

will only output two. The stated reason is that [] isn't an object (edit: "doesn't point to anything"), so puts can't do anything with it, but why is that not also true in the first case?

I tried to find an official page about puts to figure this out, and this one was no help.

Was it helpful?

Solution

The stated reason is that [] isn't an object

Stated where?

puts has a special handling for arrays. When you pass it an array, it prints each element on a new line. You pass it an array with zero elements, it prints zero lines.

OTHER TIPS

puts with an array will print one line per element. No element, no lines.

EDIT: What I just said is documented in your link:

If called with an array argument, writes each element on a new line.

The link your shared, states:

If called with an array argument, writes each element on a new line.

puts []

means, you are calling puts with empty array. i.e. no elements to print. and that's what happened.

puts arr

is like

arr.each { |e| puts e }

You can do something like this by yourself:

def p(s)
  if s.respond_to? 'each'
    s.each { |e| p e }
  else
    puts s
  end
end

p 'hello' # prints line with 'hello'
p [] # prints nothing
p [1, 2] # prints 2 lines with 1 and 2

Puts with no arguments has special behaviour - i.e. print new line. In all other cases, it treats all arguments as an array, and maps these arguments to strings using #to_s, and outputs each string on a new line. That's why you get no output when calling puts []. If you want to have a new line in the output, you can either call puts with no arguments (it's obvjous), or use splat operator with empty array, like this: puts *[].

You can write your own implementation of puts in order to understand things better.

  def my_puts(*args)
    STDOUT.write("args is #{args.inspect}\n")
    if args.empty?
      STDOUT.write("\n")
    else
      args.each { |arg| STDOUT.write("#{arg.to_s}\n") }
    end
  end


1.9.3p194 :039 > my_puts
args is []

 => 1 
1.9.3p194 :040 > my_puts []
args is [[]]
[]
 => [[]] 
1.9.3p194 :041 > my_puts *[]
args is []

 => 1 
1.9.3p194 :042 > my_puts 1,2,3
args is [1, 2, 3]
1
2
3
 => [1, 2, 3] 
1.9.3p194 :043 > my_puts [1,2,3]
args is [[1, 2, 3]]
[1, 2, 3]
 => [[1, 2, 3]] 
1.9.3p194 :044 > my_puts *[1,2,3]
args is [1, 2, 3]
1
2
3
 => [1, 2, 3] 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top