Perchè il ciclo For in Ruby è sconsigliato?

Ciao.
Su un libro che sto leggendo per imparare Ruby s’è scritta la seguente
affermazione:

Il ciclo for è implementato internamente tramite l’iteratore proprio
dell’oggetto preso in considerazione. Per questo motivo, e anche per
mantenere il codice più vicino alla filosofia di Ruby, sconsigliamo un
uso massiccio dei costrutti for: è molto meglio usare i blocchi e gli
iteratori.

Io adesso non capisco le seguenti cose:

  • Cosa vuol dire che il ciclo for è implementato internamente tramite
    l’iteratore proprio dell’oggetto preso in considerazione?
  • Perchè sono meglio gli iteratori che i cicli for?

Ciao.
KioSirio

Un iteratore “astrae” dalla logica di implementazione della
sottostante struttura dati, mentre con il ciclo for faresti l’esatto
contrario (ma ciò non accade in Ruby, che anche per il ciclo for usa
l’iteratore fornito dall’oggetto).

E’ la stessa differenza tra “per ogni bottone della giacca: cucilo” e
“numerando da 0 ad N-1 i bottoni della giacca: cuci il bottone
i-esimo” :wink:

Il 08 giugno 2010 17.35, Ivan m. Greggio [email protected] ha
scritto:

Io adesso non capisco le seguenti cose:
[email protected]
http://lists.ruby-it.org/mailman/listinfo/ml


Carlo P.
email: [email protected]
twitter: @carlopecchia

2010/6/8 Ivan m. Greggio [email protected]:

Io adesso non capisco le seguenti cose:

  • Cosa vuol dire che il ciclo for è implementato internamente tramite
    l’iteratore proprio dell’oggetto preso in considerazione?

il metodo #each di un’oggetto è quello che fa l’iterazione, for è
quello che si chiama “syntax sugar” ma ruby sotto sotto usa each:

a=Object.new
=> #Object:0x1b99064
def a.each() yield “primo”; yield “secondo”; yield “terzo” end
=> nil
for i in a
print i
end
primosecondoterzo=> nil

  • Perchè sono meglio gli iteratori che i cicli for?

è solo che i metodi con i blocchi sono più generali. Se vuoi fare
un’iterazione usi #each se vuoi trasformare una sequenza usi #map e se
vuoi filtrarla usi #filter, quindi li avrai sempre in giro per il
codice e può essere più consistente se usi #each invece del for.
Ma come ti hanno già detto, è solo una questione stilistica fai come ti pare
:slight_smile:

Nonostante apprezzi i blocchi, trovo il for leggermente più leggibile e
veloce da scrivere sicuramente non lo sconsiglierei come fa quel libro
anche perchè usando ruby 1.8.7, il for è più veloce del 30%

                       user     system      total        real

For: 12.421000 0.000000 12.421000 ( 12.421160)
Each: 16.547000 0.000000 16.547000 ( 16.577122)

Usando ruby 1.9.1 p368 invece siamo li, è più veloce l’each dell’11%:

                       user     system      total        real

For: 8.593000 0.000000 8.593000 ( 8.593035)
Each: 7.625000 0.000000 7.625000 ( 7.639989)

Questo è lo script:

require “benchmark”
include Benchmark

n=100_000_000
elements=Array.new(n, ‘’)

Benchmark.bm(21, “— Total:”) do|b|
b.report(“For:”) do
for element in elements
element
end
end

b.report(“Each:”) do
elements.each do |element|
element
end
end
end

Ivan M. wrote:

Ciao.
Su un libro che sto leggendo per imparare Ruby s’è scritta la seguente
affermazione:

Il ciclo for è implementato internamente tramite l’iteratore proprio
dell’oggetto preso in considerazione. Per questo motivo, e anche per
mantenere il codice più vicino alla filosofia di Ruby, sconsigliamo un
uso massiccio dei costrutti for: è molto meglio usare i blocchi e gli
iteratori.

Io adesso non capisco le seguenti cose:

  • Cosa vuol dire che il ciclo for è implementato internamente tramite
    l’iteratore proprio dell’oggetto preso in considerazione?
  • Perchè sono meglio gli iteratori che i cicli for?

Ciao.
KioSirio

Per la prima domanda significa che se hai un oggetto iterabile ottenuto
ad esempi con una find(:all) puoi iterare su questo oggetto in questo
modo:

oggetto.each do |elemento|
elemento.descrizione = ‘pippo’ # così assegni pippo al campo
‘descrizione’
# di ogni elemento contenuto in
“oggetto”
end

Per la seconda domanda non saprei ma credo solo che sia una questione di
stile di programmazione, nessuno ti vieta di utilizzare il for se vuoi
farlo.

Ciao Pietro,
ho dimenticato di specificare la patch 249 per ruby 1.8.7 ma come come
hai letto, ho specificato le versioni e indicato le differenze, non
dovrebbero generare confusione, anzi.
Non ho mai avuto occasione di gestire così tante iterazioni in una sola
volta ma quello è un test usato per evidenziare la differenza. Prova a
sommare tutte le percentuali, naturalmente anche per tutte le altre
differenze apparentemente banali (operazioni matematiche, concatenamenti
di stringhe ecc.) …una procedura può impiegare mooolto tempo, in
relazione alla complessità .
Nell’azienda dove lavoro, ho creato procedure batch in ruby che devono
elaborare molti dati ed ho cercato di ottimizzare ogni singola
operazione. Trattandosi poi di ambie-nti di produzione, non si cambia
interprete facilmente quindi è un lavoro che si sfrutta per molto tempo.
Con quell’esperienza avevo anche scritto un articolo sul mio umile blog:
http://mastrodonato.info/index.php/2009/08/quattro-interpreti-ruby-a-confronto/

Il 09 giugno 2010 11.27, Marco M. [email protected]
ha scritto:

Nonostante apprezzi i blocchi, trovo il for leggermente più leggibile e
veloce da scrivere sicuramente non lo sconsiglierei come fa quel libro
anche perchè usando ruby 1.8.7, il for è più veloce del 30%

Ciao,

i consigli relativi alla performance hanno quasi sempre vita breve,
perché appena esce una nuova release cambia tutto, e in ogni caso è
veramente raro che facciano questa gran differenza (se nel tuo
programma c’è un ciclo su un array di 100’000’000 di elementi, molto
probabilmente c’è un grosso problema a prescindere da come lo fai!).
La comunità java continua tutt’oggi a essere devastata dai danni di
consigli sulla performance che valevano per versioni come la 1.2 e che
oggi sono solo distruttivi.

Diverso è per le considerazioni stilistiche, che però sono molto
personali, specie per un linguaggio come Ruby.

                      user     system      total        real

For: 12.421000 0.000000 12.421000 ( 12.421160)
Each: 16.547000 0.000000 16.547000 ( 16.577122)

Usando ruby 1.9.1 p368 invece siamo li, è più veloce l’each dell’11%:

                      user     system      total        real

For: 8.593000 0.000000 8.593000 ( 8.593035)
Each: 7.625000 0.000000 7.625000 ( 7.639989)

Molto interessante: evidentemente la gestione dei block è migliorata
tantissimo.

pietro