Clase y Tipo de un Objeto. Polimorfismo

To determine the class of an object in Ruby, simply ask for it:

o = "test"  # This is a value
o.class     # Returns an object representing the String class

We can ask any class what its superclass is:

o.class                       # String: o is a String object
o.class.superclass            # Object: superclass of String is Object
o.class.superclass.superclass # nil: Object has no superclass

In Ruby 1.9 and later, Object is no longer the root of the class hierarchy:

Object.superclass             # BasicObject: Object has a superclass in 1.9
BasicObject.superclass        # nil: BasicObject has no superclass

So a particularly straightforward way to check the class of an object is by direct comparison:

o.class == String       # true if is o a String

The instance_of? method does the same thing and is a little more elegant:

o.instance_of? String   # true if o is a String

Usually when we test the class of an object, we would also like to know if the object is an instance of any subclass of that class. To test this, use the is_a? method, or its synonym kind_of? :

x = 1                    # This is the value we're working with
x.instance_of? Fixnum    # true: is an instance of Fixnum
x.instance_of? Numeric   # false: instance_of? doesn't check inheritance
x.is_a? Fixnum           # true: x is a Fixnum
x.is_a? Integer          # true: x is an Integer
x.is_a? Numeric          # true: x is a Numeric
x.is_a? Comparable       # true: works with mixin modules, too
x.is_a? Object           # true for any value of x

The Class class defines the === operator in such a way that it can be used in place of is_a?:

Numeric === x            # true: x is_a Numeric

Clase y Vida de un Objeto

Every object has a well-defined class in Ruby, and that class never changes during the lifetime of the object.

Que es un Tipo

When we talk about the type of an object, we mean the set of behaviors that characterize the object

Another way to put it is that the type of an object is the set of methods it can respond to

(This definition becomes recursive because it is not just the name of the methods that matter, but also the types of arguments that those methods can accept.)

¿Puedo llamar a este método sobre este objeto?

In Ruby programming, we often don't care about the class of an object, we just want to know whether we can invoke some method on it.

  1. Consider, for example, the << operator.

    Arrays, strings, files, and other I/O-related classes define this as an append operator.

    If we are writing a method that produces textual output, we might write it generically to use this operator.

  2. Then our method can be invoked with any argument that implements <<. We don't care about the class of the argument, just that we can append to it. We can test for this with the respond_to? method:

    o.respond_to? :"<<"  # true if o has an << operator
  3. Este método funciona tanto con cadenas como con arrays, listas, etc. es un método polimorfo. Polymorphism is the provision of a single interface to entities of different types.

The shortcoming of this approach is that it only checks the name of a method, not the arguments for that method:

  1. For example, Fixnum and Bignum implement << as a left-shift operator and expect the argument to be a number instead of a string.

  2. Integer objects appear to be appendable when we use a respond_to? test, but they produce an error when our code appends a string.

There is no general solution to this problem, but an ad-hoc remedy, in this case, is to explicitly rule out Numeric objects with the is_a? method:

o.respond_to? :"<<" and not o.is_a? Numeric

Another example of the type-versus-class distinction is the StringIO class (from Ruby's standard library).

  1. StringIO enables reading from and writing to string objects as if they were IO objects.

  2. StringIO mimics the IO API—StringIO objects define the same methods that IO objects do.

  3. But StringIO is not a subclass of IO.

  4. If you write a method that expects a stream argument, and test the class of the argument with is_a? IO, then your method won't work with StringIO arguments.

Focusing on types rather than classes leads to a programming style known in Ruby as "duck typing."

Repasa la sección Comprobación de Tipos y Tipado Pato (Duck Typing) 14.1.8.

El tipo de un objeto es el conjunto de conductas que caracterizan al objeto. Es el conjunto de métodos a los que puede responder.

Casiano Rodriguez León 2015-01-07