tags:

views:

211

answers:

2

I am using Ruby 1.8.6 for the following code:

# Create an array and override the #to_s on that object
thing = [1,2,3]
def thing.to_s
  'one'
end

print "Using print: "
print thing

puts
puts "Using puts: "
puts thing

Output:

Using print: one
Using puts: 
1
2
3

So thing is an Array and I have overridden thing#to_s. print seems to use my overriden implementation while puts does not. Why?

I have followed the source code of Kernel#puts and Kernel#print (which are C-implementations) and see that they are very different implementations. I want to know what might be the design-decision (if any) behind this?

By the way, if I create thing as an instance of another class I wrote (or as a Hash/String/other-classes I tried), both print and puts use the overridden implementation of to_s.

+1  A: 

From the Ruby Programming Language:
alt text

Output streams are appendable, like strings and arrays are, and you can write values to them with the << operator. puts is one of the most common output methods. It converts each of its arguments to a string, and writes each one to the stream. If the string does not already end with a newline character, it adds one. If any of the arguments to puts is an array, the array is recursively expanded, and each element is printed on its own line as if it were passed directly as an argument to puts. The print method converts its arguments to strings, and outputs them to the stream. If the global field separator $, has been changed from its default value of nil, then that value is output between each of the arguments to print. If the output record separator $/ has been changed from its default value of nil, then that value is output after all arguments are printed.

As for design decisions, that I do not know.

JRL
In case anybody missed it in the rather verbose explanation: `puts` special-cases arrays so that if you pass one as an argument, puts does `arg.each {|i| puts i}`.
Chuck
Yes that explains this. However, with Ruby's POLS (Principle of Least Surprises) in mind, I expected puts to use the #to_s method I wrote.Maybe, there is a case for the puts method to have another special case. If the object has a to_s defined use that otherwise go through the routine. At the same time I can see that puts is probably not used in production code too much (you'd be better off using loggers unless you want to write to files) so this implementation is fine.
arnab
+1  A: 

Oh boy ... This has already been the topic of a countless number of endless threads on the ruby-talk mailinglist, the ruby-core mailinglist and a gazillion of blogs.

The gist of it is that puts special cases Arrays. Why it special cases those, why it special cases only those (as opposed to, say, all Enumerables), why it special cases those (and not, say, print), nobody really knows. It is the way it is.

BTW, since you mentioned the POLS: the Ruby community has always made it very clear that the POLS only applies to matz. So, Ruby is about not surprising matz. If you or me or anybody else is surprised, that doesn't count.

Jörg W Mittag