Proc e metodi sono entrambi oggetti in ruby. Le Proc rappresentano, come prima cosa, delle funzioni anonime, cioe’ che possono essere definite senza un nome particolare. Si fa uso di
Proc tutte le volte che si passa un blocco in input ad una funzione come ad esempio each.
Proc puo’ avvenire in tre modi:
# primo metodo prc=Proc.new do |arg| ...codice.. end # secondo metodo prc=proc do |arg| ...codice.. end # terzo metodo prc=lambda do |arg| ...codice.. end
lambda &blk e proc &blk sono effettivamente sinonimi, mentre la creazione di un oggetto Proc con Proc.new ha una differenza sottile.
La differenza e’ nel passaggio dei parametri:
>> p=Proc.new {|a,b| puts a,b } => #<Proc:0x401f9570@(irb):1> >> f=lambda {|a,b| puts a,b } => #<Proc:0x401f61b8@(irb):2> >> p.call 1,2 1 2 => nil >> f.call 1,2 1 2 => nil >> p.call 1 1 nil => nil >> f.call 1 ArgumentError: wrong number of arguments (1 for 2) from (irb):2 from (irb):2:in `call' from (irb):6
Cioe’ proc e lambda si comportano come i normali metodi, richiedendo un numero esatto di parametri, mentre l’altra forma e’ piu’ elastica :-).
Per chi si chiedesse cosa cavolo e’ lambda: si tratta del nome che viene dato alle funzioni anonime in altri linguaggi, come ad esempio LISP.
Proc per essere applicato a dei parametri richiede l’uso del metodo call(). Dunque, non scriveremo
p= lambda {|z| print z } p(10) # sintassi come in python o schemeScriveremo invece
p= lambda {|z| print z } p.call(10) # simile a funcall in Common LISPLa prima sintassi potra’ sembrare piu’ conveniente, ma in ruby e’ impossibile, visto che le parentesi sono opzionali. Come si farebbe a capire se
print deve essere usata come funzione o si deve usare il suo valore di ritorno?
Quantomeno, ruby ci permette di “imitare” la sintassi classica, usando delle parentesi quadre:
p= lambda {|z| print z } p[10] # equivalente a p.call(10)Un oggetto di tipo metodo invece viene creato cosi’:
met=method(:nomemetodo)oppure
met=oggetto.method(:nomemetodo)Una volta creati, questi oggeti funzionano praticamente in maniera identica:
def fun(a) a**2 end nil oggetto=method :fun # #<Method: Object#fun> oggetto.call(10) # 100 oggetto[10] # uguale a call()
Un ultima cosa: le funzioni che accettano in input un blocco si lamenteranno se provate a passargli un oggetto Proc; o Method. Per espandere questi oggetti/funzione in blocchi vi bastera’
mettere davanti al nome della variabile il simbolo “&“