Ruby: métodos de clase y métodos de instancia – cambiar la palabra es “La he liado parda”


med_Pragmatic.Bookshelf.Programming.Ruby.Jul.2013.ISBN.1937785491.pdfEn ocasiones es difícil explicarse por medio de la palabra, eso lo tengo muy claro, pero si a esto le sumas el poner la palabra definida erróneamente, puede llevar a términos que no es lo mismo, confundir al que lo está leyendo y piensas, “la he liado parda”. El caso es que he cometido el error de cambiar una palabra y poner que una solución a un problema (no es relevante el problema de origen para lo que voy a contar) era un método de clase Myclass.method en vez de un método de instancia Myclass#method  y como es lógico no es lo mismo, eso está claro, pero para que no te pase a ti lo mismo, voy a tratar de explicarlo, aunque lo de equivocarse, si eres humano, en ocasiones te puede ocurrir.

Quiero tratar el tema desde dos puntos de vista diferentes y quería hablar de los métodos de instancia y los métodos de clase, cuando tenemos una clase sin herencia y la otra es cuando tenemos herencia y explicar que self.class.method no es lo mismo que ClassName.method cuando hacemos herencia entre clases. Otro tema que quiero explicar es la concatenación de métodos, mediante los métodos de clase.

Veamos un primer paso sin herencia en la definición de la clase Foo, en las llamadas de método de instancia y de método de clase, por ejemplo tenemos:

class Foo
    def self.some_class_method
         puts self
    end

    def some_instance_method
        self.class.some_class_method
    end
end

Foo.some_class_method

Foo.new.some_instance_method

En el primer caso, hacer la llamada con Foo.some_class_method, puedes ver que no hemos instanciado la clase Foo, por tanto es un método de clase y tenemos como resultado “Foo”. En el segundo caso, hacer la llamada con Foo.new.some_instance_method, puedes observar que hemos hecho una instancia a la clase Foo y se trata de un método de instancia y como resultado tenemos Foo igualmente, pero para obtener el mismo resultado hemos hecho la llamada al método de some_instance_method, que a su vez dispone de la llamada a self.class.some_class_method, y ¿cómo llegamos para que salga Foo?  la explicación es, self.class es Foo, la clase instanciada, le estamos diciendo que llame a la clase Foo.some_class_method, devolviendo finalmente “Foo”. 

Veamos cómo sería ahora con herencia cada una de las llamada de  método de clase y método de instancia:

class Foo
    def self.default_make
          “Foo”
    end

    def foo_one
         self.class.default_make
    end

    def foo_two
         Foo.default_make
    end
end
class BigFoo < Foo
       def self.default_make
            “BigFoo”
       end
end

Ahora instanciamos la clase BigFoo:

b=BigFoo.new

b.foo_one => “BigFoo”

b.foo_two => “Foo”

El resultados que tenemos es en el primer caso, b.foo_one es “BigFoo” y en el segundo caso b.foo_two tenemos como resultado “Foo”. La explicación de los resultados es, para el caso b.foo_one, primero instanciamos la clase BigFoo en b b=BigFoo.new y llamamos a b.foo_one que es un método que se encuentra en la clase Foo y la hemos heredado en BigFoo, por tanto cuando llega a foo_one, tenemos la llamada de self.class.default_make que en nuestro caso self.class es BigFoo y hace la llamada al método  de clase que tenemos en BigFoo, def self.default_make, por tanto llamará al método de clase BigFoo y obteniendo el resultado de “BigFoo”. ¿Qué pasa si hacemos la misma llamada desde Foo? Si ahora hacemos la llamada a Foo.foo_one, la llamada a self.class.default_make ahora self.class es Foo, por lo que llamará al método de clase self.default_make devolviendo “Foo”.

20140310_221009

Para la llamada del segundo caso, b.foo_two, nos vamos a la clase que hereda BigFoo que es Foo y vemos el método foo_two, que tiene una llamada a Foo.default_make y que llamamos dentro de la clase Foo a un método de clase self.default_make, dando como resutado final “Foo”. Aquí está claro que no podríamos hacer la llamada Foo.foo_two, nos daría un error. Ahora ya tienes claro, cómo son las llamadas a métodos de instancia y métodos de clase sin herencia, para el primer caso de llamada a métodos de clase Foo.some_class_method y métodos de instancia Foo.new.some_instance_method y en los casos de herencia, recuerda que no es lo mismo cuando estamos llamando a un método de clase en una misma clase en métodos como some_instance_method de la primera clase Foo, que cuando lo hacemos desde una clase BigFoo que hereda de Foo. En la imagen te dejo un esquema de las llamadas pare que veas el recorrido de ambos casos de b.foo_one y b.foo.two.

Para terminar, quería explicar la concatenación de métodos, mediante los métodos de instancia con self, que es la forma de hacerlos. Vemos un ejemplo:

class Foo
  def method_one
    # do something
    self
  end

  def method_two
    # do something
    self
  end

  def method_three
    # do something
    self
  end

  # more methods...
end

foo = Foo.new

foo.method_one.method_two.method_three

Vamos a poner otro ejemplo. Imagina que queremos que un método nos calcule el doble y otro método concatenado nos calcule la mitad para quedarnos igual que al principio, un poco chorra pero sirve para que lo veas claro:

class Numeric      

      def double          

             self * 2      

      end      

      def half(current)          

           self / current      

      end

end

20.double.half(2) => nos devuelve 20

Vamos a ver otro ejemplo más:

class Fixnum
  def square
    self**2
  end
end

class Array
  def sum
    reduce(0, &:+)
  end
end

[1,2].sum.square # devolviendo 9

Espero que tengas ahora más claro los casos de métodos de clase, métodos de instancia y concatenación de métodos.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s