Assad Ebrahim
Assad Ebrahim

Reputation: 6361

Ruby as a "pure" object oriented language --- inconsistency with Ruby puts?

I've often read that Ruby is a pure object oriented language since commands are typically given as messages passed to the object.

For example:

In Ruby one writes: "A".ord to get the ascii code for A and 0x41.chr to emit the character given its ascii code. This is in contrast to Python's: ord("A") and chr(0x41)

So far so good --- Ruby's syntax is message passing.

But the apparent inconsistency appears when considering the string output command:

Now one has: puts str or puts(str) instead of str.puts

Given the pure object orientation expectation for Ruby's syntax, I would have expected the output command to be a message passed to the string object, i.e. calling a method from the string class, hence str.puts

Any explanations? Am I missing something?

Thanks

Upvotes: 2

Views: 288

Answers (4)

sawa
sawa

Reputation: 168199

Printing something to somewhere at least involves two things: what is written and where it is written to. Depending on what you focus on, there can be different implementations, even in OOP. Besides that, Ruby has a way to make a method look more like a function (i.e., not being particularly tied to a receiver as in OOP) for methods that are used all over the place. So there are at least three logical options that could be thought of for such methods like printing.

  • An OOP method defined on the object to be printed
  • An OOP method defined on the object where it should be printed
  • A function-style method

For the second option, IO#write is one example; The receiver is the destination of writing.

The puts without an explicit receiver is actually Kernel#puts, and takes neither of the two as the arguments; it is an example of the third option; you are correct to point out that this is not so OOP, but Matz especially provided the Kernel module to be able to do things like this: a function-style method.

The first option is what you are expecting; it is nothing wrong. It happens that there is no well known method of this type, but it was proposed in the Ruby core by one of the developers, but unfortunately, it did not make it. Actually, I felt the same thing as you, and have something similar in my personal library called Object#intercept. A simplified version is this:

class Object
  def intercept
    tap{|x| p x}
  end
end

:foo.intercept # => :foo

You can replace p with puts if you want.

Upvotes: 0

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230461

I would have expected the output command to be a message passed to the string object, i.e. calling a method from the string class, hence str.puts

This is incorrect expectation, let's start with that. Why would you tell a string to puts itself? What would it print itself to? It knows nothing (and should know nothing) of files, I/O streams, sockets and other places you can print things to.

When you say puts str, it's actually seen as self.puts str (implicit receiver). That is, the message is sent to the current object.

Now, all objects include Kernel module. Therefore, all objects have Kernel#puts in their lists of methods. Any object can puts (including current object, self).

As the doc says,

puts str

is translated to

$stdout.puts str

That is, by default, the implementation is delegated to standard output (print to console). If you want to print to a file or a socket, you have to invoke puts on an instance of file or socket classes. This is totally OO.

Upvotes: 8

Jo Erlang
Jo Erlang

Reputation: 327

puts is a method on an output streams e.g.

$stdout.puts("this", "is", "a", "test")

Upvotes: 2

Chris Heald
Chris Heald

Reputation: 62668

Ruby isn't entirely OO (for example, methods are not objects), but in this case, it is. puts is Kernel#puts, which is shorthand for $stdout.puts. That is, you're calling the puts method of the $stdout stream and passing a string as the parameter to be output to the stream. So, when you call

puts "foo"

You're really calling:

$stdout.puts("foo")

Which is entirely consistent with OO.

Upvotes: 5

Related Questions