format internet:

…please wait (39% completed)…

destructores en ruby

Posted by javier ramirez on September 30, 2007

Viniendo de otros lenguajes de programación, cuando empecé con Ruby echaba de menos los métodos destructores de objetos. Igual que existe un método initialize, esperaba que hubiera un método finalize al que se invocase justo antes de que el garbage collector pasase a limpiar los objetos no usados.

Buscando un poco, di con la clase ObjectSpace, con la que se pueden hacer algunas cosas interesantes, como por ejemplo recorrer todos los objetos que existen en memoria en un momento determinado. Esta clase tiene un método, define_finalizer, que permite definir un hook que se llamará cuando el objeto se libere.

El problema es que, por como está implementado, cuando se invoca a este hook el objeto ya no puede existir en memoria, porque si existiese habría una referencia a ese objeto y entonces el garbage collector no lo limpiaría nunca. La verdad es que este comportamiento es bastante mejorable y, como bien dice aquí Charles Nutter, no es lo único mejorable de la clase ObjectSpace.

El caso es que ese comportamiento es el que hay, y con eso tenemos que jugar. Para el caso más sencillo, es tan simple como lo siguiente.

  a='cadena de prueba'
  ObjectSpace.define_finalizer(a,proc{|id| puts "finalizando el objeto #{id}"})
  a=nil
  GC.start

Si ejecutamos eso en la consola, podremos ver cómo, cuando pasamos el collector, se muestra la cadena indicando que se ha destruído.

Si lo que queremos es llamar a un método concreto, hay que tener en cuenta que el objeto ya se habrá destruído cuando se invoque su finalizador, así que podremos llamar solamente a métodos no asociados a la instancia. Lo normal en ese caso es llamar a métodos de la clase de este objeto. Por ejemplo

class TestClass
  def initialize 
    ObjectSpace.define_finalizer(self,self.class.method(:terminate).to_proc)
  end

  def TestClass.terminate(object_id)
    puts "se ha destruÃ�­do el objeto {#object_id}"
  end
end

En el método terminate podríamos hacer lo que necesitásemos, siempre teniendo en cuenta que el objeto ya no existe. Si se tratase de liberar recursos abiertos a la hora de inicializarlo, que es el caso más común, se podría usar una Hash definida como variable de clase y guardar la referencia a los recursos que se abren usando el object_id como clave. De este modo, al llamar al método terminate, podríamos acceder con el id a esa Hash para poder liberar el recurso que nos interese.

En cualquier caso, hay que decir en defensa de Ruby que para muchos de los casos donde en otros lenguajes de programación usaríamos destructores de objetos, en Ruby usaremos bloques, quedando un código mucho más legible.

Por ejemplo

FantasticConnection.open(end_point) do |conn|
  conn.send(my_data)
end

searchwords: finalizer, finalize, destructor, constructor, garbage collector, colector de basura, ObjectSpace

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: