Why does the Ruby Array class have to_a and to_ary methods?

Are there any use cases that we will call Array.to_a

and Array.to_ary

for an object that is already an array?

If not, why do these methods exist in the Array class?

+3


source to share


3 answers


Are there any use cases that we will call these coercion methods (Array.to_a and Array.to_ary) on an object that is already an array?

Yes: in Ruby, you don't care at all which class is an instance of an object. Just what he can do. So, you don't care "whether this object can convert itself to an array". Obviously an array can convert itself to an array, so it must have these methods.

A slightly longer answer: if we don't care which class is an object instance ... then why do we care if it can convert itself to an array? Well, that's a pragmatic choice. From a purely OO perspective, it doesn't matter. But there are certain operations that are implemented deep inside the core of the execution engine, for which the object must be of a certain class for efficiency and performance reasons. In other words, sometimes objects don't work, you need an abstract data type.

For example, there are certain operations within the Ruby execution engine that take advantage of the fact that they know about the Array

s internal memory layout . Obviously, these operations will collapse horribly if you pass them something that is not Array

, and they dig into that object's memory. From a pure OO perspective, these operations shouldn't be aware of this, and they should use an open interface Array

, but alas, they don't. But in order to give you (the programmer) an escape hatch for your own array-like objects, these operations will allow you to convert yourself to first by Array

calling to_ary

.

In other words, implementation to_ary

means your object is a kind of array. Obviously an array is sort of an array, so it answers to to_ary

.



There are other similar conversion methods in Ruby: to_str

for strings, to_int

for integers, to_float

for floats, to_proc

for "functions".

There are also one-letter variants. Long options mean "I really am an array, I just am not an instance of the class Array

." Instead, the short cuts mean "I can sort myself as an array somehow."

You can see what is most obvious with nil

: it answers to_i

(because its sorta-sorta makes sense to represent it nil

as an integer 0

), but it doesn't answer to_int

(because it's nil

not an integer in other clothes, it's something completely different).

What arrays, integers, etc. also realize to_a

, to_ary

, to_i

, to_int

and so on, means that you can handle all the objects similar to the array, the same, polymorphonuclear. It doesn't matter if it's an array, stack, set, tree, enumerator, range, or whatever. As long as it can be sorted as an array, it will respond to to_a

, and as long as it is actually an array (even if its class is not Array

), it will respond to to_ary

, and you don't need to check, because it doesn't matter.

Note, however, that these situations should ideally be rare. In general, you should take care of whether the object can iterate over itself (i.e. responds to each

). In fact, most of the things you can do with an array you can also do with anyone else Enumerable

without using to_ary

or to_a

. This should be the last resort.

+9


source


Array implements to_a

and to_ary

because it allows for cleaner methods that coerce arguments to specific types.

For example, what if you have a method:

def foo(object)
  #does some work on object that requires object acts like an array.
  ...
end

      

and wanted to use this method for sets created from elsewhere in your code.



One way to do this is to do it object.to_a

before performing the operation:

def foo(object)
  array = object.to_a
  ...
end

      

If Array didn't implement to_a

, then you need to check:

def foo(object)
  array = object.to_a if object.respond_to?(:to_a)
  ...
end

      

0


source


I think this is (by the way) to avoid a special case for nil

.

Let's say foo

is a method that can return an array or nil

. The below snippet will fail:

foo.each { |x| puts x }

      

If you have Array

n't implemented the method to_a

, you probably have to write something like this, which is a bit ugly in my opinion:

(foo || []).each { |x| puts x }

      

Instead of this:

foo.to_a.each { |x| puts x }

      

Similarly, it Integer

has a method to_i

, but String

has a method to_s

, etc.

0


source







All Articles