Distruttore di classi

Per inizializzare una classe c’è “initialize”, ma per “distruggerla”?
Lo so che il Garbage collection fa un ottimo lavoro, ma non sa quali
sono le operazioni che la mia classe deve fare nel momento in cui viene
eliminata.

Ciao Michele.

On Tue, Sep 16, 2008 at 8:49 AM, Michele C. [email protected]
wrote:

Per inizializzare una classe c’è “initialize”, ma per “distruggerla”?
Lo so che il Garbage collection fa un ottimo lavoro, ma non sa quali
sono le operazioni che la mia classe deve fare nel momento in cui viene
eliminata.

qui: http://pleac.sourceforge.net/pleac_ruby/classesetc.html
ho trovato quest’esempio:

class MyClass
def initialize
ObjectSpace.define_finalizer(self,
self.class.method(:finalize).to_proc)
end
def MyClass.finalize(id)
puts “Object #{id} dying at #{Time.new}”
end
end

test code

3.times {
MyClass.new
}
ObjectSpace.garbage_collect

tuttavia, nella stessa pagina si spiega che non c’è modo di sapere
quando il garbage collector sarà invocato, a meno di non invocarlo
esplicitamente.

pertanto, se la tua classe deve fare delle operazioni quando non viene
più usata, è sempre meglio invocare esplicitamente un qualche metodo
della stessa, in modo che chiuda le eventuali connessioni, i file
temporanei o quant’altro.

questo perché, a meno di esempi un po’ sciocchi, come quello
precedente, o come, che so, a = MyClass.new; a = 3, spesso gli oggetti
rimangono in vita per più tempo di quello che ci si potrebbe aspettare
(ad esempio, per tutta la durata di esecuzione di un metodo, se non la
classe intera).

Il giorno 16/set/08, alle ore 08:49, Michele C. ha scritto:

Per inizializzare una classe c’è “initialize”, ma per “distruggerla”?
Lo so che il Garbage collection fa un ottimo lavoro, ma non sa quali
sono le operazioni che la mia classe deve fare nel momento in cui
viene
eliminata.

In generale, non e’ una buona pratica di design compiere operazioni
(pertinenti il dominio del tuo problema) in un distruttore (che e’
fatto per operazioni di cleanup come rilasciare risorse di memoria).

Meglio specificare un metodo (#die, #end, #close) che sancisce la
“morte” della tua istanza nel mondo reale e chiamarlo esplicitamente
tenendolo distinto dal metodo che sancisce la morte del tuo oggetto
nella memoria (i due eventi potrebbero essere per scelta del GC anche
molto distinti temporalmente).

Se poi ti annoi a chiamarlo sempre esplicitamente puoi creare un po’
di syntactic sugar (tipo File>>open) in modo che all’interno di un
blocco sei sicuro che il tuo metodo venga eseguito.

Cmq se proprio vuoi farti male il metodo e’ YourClass.finalize(id)
dove id e’ il tuo oggetto morente.

Luigi P.

Per curiosità, cosa dovrebbe fare la tua classe quando viene distrutta
una sua istanza?

Luca

blog: www.lucaguidi.com
Pro-Netics: www.pro-netics.com
Sourcesense - making sense of Open Source: www.sourcesense.com

visto, funziona, me c’è un problema…
le variabili di istanza non riesco a gestirle.
Prova questo:
class MyClass
attr_reader :pippo
def initialize(pippo)
@pippo = pippo
ObjectSpace.define_finalizer(self,self.class.method(:finalize).to_proc)
end

def self.finalize(id)
    puts "Object #{id} dying at #{Time.new}"
    puts "qui 1"
    puts "init close : " + @pippo
    puts "qui 2"

end

end

test code

a = MyClass.new(‘a’)
a = nil
puts ‘FUORI DALL’OGGETTO’
puts ‘’

ObjectSpace.garbage_collect

visualizza le prime due puts (di finalize) la terza no.

Ciao Michele.

Il giorno 16/set/08, alle ore 12:42, Michele C. ha scritto:

La classe mi serve per gestire file excel, il distruttore mi serve per
chiuder l’area di lavoro e il file, dopo la chiusura libero le risorse
impostando a nil.

Ok, quindi non ti serve un distruttore ma un metodo per terminare la
tua sessione excel.

def elabora
yield
fine()
end

Ottimo lavoro! Ti conviene inserire il tutto in un blocco begin/
rescue cosi’ chiudi excel anche se c’e’ un errore nel blocco eseguito
da yield.
Ancora: puoi passare self allo yield cosi’ da disaccoppiare meglio il
blocco eseguito da quello che contiene la chiamata ad elabora.

Non c’e’ nessun buon motivo per inserire GC.start (il collector sa
lui quando ripulire). Se ne hai uno inserisci immediatamente un
commento altrimenti sarai sbalordito e avrai bisogno di un buon vino
quando rivedrai quel codice tra 3 mesi :wink:

La classe mi serve per gestire file excel, il distruttore mi serve per
chiuder l’area di lavoro e il file, dopo la chiusura libero le risorse
impostando a nil.
La GC non mi rilasciava il file excel appena creato quando o mettevo a
nil l’istanza della classe Xls.
Comunque la soluzione c’è:

------------- CLASSE

require ‘win32ole’
class Xls
attr_reader :nome_file, :sheet , :excel, :workbook
def initialize(nomefile, fogli)
[…}
end

def elabora
yield
fine()
end

def scrivi_cella(row, col, valore)
@sheet.cells(row,col).value = valore
end

[…]

private
def fine
@workbook.close
@workbook = nil
@excel.Quit
@excel = nil
GC.start #Force Garbage Colelction
end
end

---------------------- EOF

x = Xls.new("#{RAILS_ROOT}/public/temp/test_001.xls", fogli)
x.elabora do
x.scrivi_cella(1,1, ‘michele’)
end

P.S. non ho incollato tutta la classe per motivi di spazio, se ti serve
ti faccio un allegato.

Ciao Michele.

Il giorno 16/set/08, alle ore 14:50, Michele C. ha scritto:

Il primo l’ho capito :
def elabora
begin
yield
rescue
end
fine()
end

Esatto. Ovviamente fine() va chiamata un filino prima

Ah mi sono sbagliato. Meglio usare begin/ensure cosi’ #fine viene
chiamato anche se non ci sono errori.

ma la questione del self proprio no… Cosa intendi per passare self
allo yeld?

Intendo questo:

class Foo
def usefulMethod
puts “cool”
end

   def die
       puts "die"
   end

   def process
begin
           yield(self)
ensure
    die
       end

end
end

x = Foo.new

x.process { |arg|
arg.usefulMethod
}

in modo da poter anche fare Foo.new.process {|arg| … }

Ciao

Luigi P. wrote:

Il giorno 16/set/08, alle ore 12:42, Michele C. ha scritto:

La classe mi serve per gestire file excel, il distruttore mi serve per
chiuder l’area di lavoro e il file, dopo la chiusura libero le risorse
impostando a nil.

Ok, quindi non ti serve un distruttore ma un metodo per terminare la
tua sessione excel.

def elabora
yield
fine()
end

Ottimo lavoro! Ti conviene inserire il tutto in un blocco begin/
rescue cosi’ chiudi excel anche se c’e’ un errore nel blocco eseguito
da yield.
Ancora: puoi passare self allo yield cosi’ da disaccoppiare meglio il
blocco eseguito da quello che contiene la chiamata ad elabora.

Non c’e’ nessun buon motivo per inserire GC.start (il collector sa
lui quando ripulire). Se ne hai uno inserisci immediatamente un
commento altrimenti sarai sbalordito e avrai bisogno di un buon vino
quando rivedrai quel codice tra 3 mesi :wink:

Il primo l’ho capito :
def elabora
begin
yield
rescue
end
fine()
end

ma la questione del self proprio no… Cosa intendi per passare self
allo yeld?