Print uses to_s but puts does not

I want to create a MyArray that prints the array with space delimiters.
.print works but .puts doesn’t. Why? Thanks

class MyArray < Array
def initialize(x)
super
end

def to_s
    "DEBUG " + join(' ')
end

end

irb(main):057:0> load “MyArray.rb”
=> true
irb(main):058:0> a = MyArray.new([1, 2, 3, 4])
=> [1, 2, 3, 4]
irb(main):059:0> puts a
1
2
3
4
=> nil
irb(main):060:0> print a
DEBUG 1 2 3 4=> nil

Version Info

ruby --version
ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin14]

irb --version
irb 0.9.6(09/06/30)

But, what about:

class A < Array
end

a = A([1, 2, 3])

puts a #=> 1, …

It is because

puts x

is equivalent to

print(x.to_s+"\n")

Yes, this was a good question. I didn’t realise this until I did some
more testing and than I was confused as well.

Here’s a stackoverflow question which explains how to use to_s with
subclassed Arrays:
http://stackoverflow.com/questions/11463873/ruby-overriding-the-puts-method

I wonder why it’s like this? From an OO point of view it’s not a nice
solution, because puts needs to know what type of class the argument is.
There must be a pragmatic reason?

The reason’s in the documentation:
http://ruby-doc.org/core-2.2.2/IO.html#method-i-puts

It seems something like tradition, so that puts acts like C’s printf or
Javascript console.log, it wants to work on something like *args.

This has nothing to do with OOP. The “basic method” for outputting
something is IO#print. You can stick with this, if you want.

To make things easier to use in many convenient cases, Ruby also has
IO#puts, Kernel#print, Kernel#p, Kernel#pp, and several others. You can
use them, if they fit you. You can create new ones, if you are not
satisfied with them. For instance, if you have the habit to add to most
of your classes a method named :myFancyPrinting, you could add a method
of this name to, say, Kernel, and define it to invoke :myFancyPrinting
on the argument (if it is defined) and revert to, say, Kernel#puts if it
isn’t.

In your case, you are picking from the list two arbitrary methods -
Kernel#print and Kernel#puts - and wonder, why they behave differently.
Well, why should they behave the same? They serve a slightly different
purpose.

Ronald F. wrote in post #1185017:

It is because

puts x

is equivalent to

print(x.to_s+"\n")

No they are not.

irb(main):004:0> x = MyArray.new([1, 2, 3])
=> [1, 2, 3]

irb(main):005:0> puts x
1
2
3

irb(main):006:0> print(x.to_s+"\n")
DEBUG 1 2 3

How are these equivalent?

Joe, your doc link is useful. It makes “common sense” although Ronald’s
equivalence theory is what I had in mind initially. I’ll rephrase my
understanding of a new equivalence theory:

puts x

is probably equivalent to

if x.is_a? Array then
    x.each { |i| puts i.to_s }
else
    print(x.to_s+"\n")
end

I thank you both for taking the time to respond. It’s this type of
exchange and investigation that gives deep understanding.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs