Archivi categoria: Ruby

Ruby 2.1 : cosa è stato deprecato?

Sul sito di Bozhidar Batsov potete trovare un interessante articolo in cui vengono elencate le funzionalità principali deprecate con la versione 2.1 di Ruby.

In realtà non sappiamo esattamente da quale versione sono state deprecate, ma se le state usando affrettatevi a correggere il vostro codice.

  • Dir.exists? is a deprecated name, use Dir.exist? instead
  • Enumerator.new without a block is deprecated; use Object#to_enum
  • StringIO#bytes is deprecated; use StringIO#each_byte instead
  • StringIO#chars is deprecated; use StringIO#each_char instead
  • StringIO#codepoints is deprecated; use StringIO#each_codepoint instead
  • StringIO#lines is deprecated; use StringIO#each_line instead
  • File.exists? is a deprecated name, use File.exist? instead
  • Hash#index is deprecated; use Hash#key
  • ENV.index is deprecated; use ENV.key
  • IO#lines is deprecated; use IO#each_line instead
  • IO#bytes is deprecated; use IO#each_byte instead
  • IO#chars is deprecated; use IO#each_char instead
  • IO#codepoints is deprecated; use IO#each_codepoint instead
  • ARGF#lines is deprecated; use ARGF#each_line instead
  • ARGF#bytes is deprecated; use ARGF#each_byte instead
  • ARGF#chars is deprecated; use ARGF#each_char instead
  • ARGF#codepoints is deprecated; use ARGF#each_codepoint instead
  • Object#untrusted? is deprecated and its behavior is same as Object#tainted?
  • Object#untrust is deprecated and its behavior is same as Object#taint
  • Object#trust is deprecated and its behavior is same as Object#untaint
  • passing a block to String#lines is deprecated
  • passing a block to String#bytes is deprecated
  • passing a block to String#chars is deprecated
  • passing a block to String#codepoints is deprecated

 

Ruby : cicli e iteratori – parte 2

Cos’è un iteratore?  E’ semplicemente un metodo che, per mezzo dell’operatore yield trasferisce il controllo al blocco di codice che è associato al metodo stesso quando questo viene invocato ……

Quando noi scriviamo

a.map { |i|  i*5 }

Il metodo map (che è un iteratore) trasferisce il controllo al blocco, cioè alla porzione di codice delimitata da {}.

In che senso trasferisce il controllo? perchè? quante volte? Questo dipende dal metodo.

each

l’iteratore più semplice è each. Questo metodo trasferisce il controllo al blocco per ogni elemento contenuto nella collection al quale è applicato.

[1,2,3].each { |x| puts x }

nel blocco il costrutto |x| indica che quando il controllo viene trasferito al codice contenuto nel blocco, la variabile x contiene il valore dell’elemento sul quale la funzione collect sta iterando.

E’ come scrivere:

for x in [1,2,3] do
  puts x
end

Collect Select Inject Reject

Questi quattro iteratori li troviamo in tutti i linguaggi funzionali, magari con nomi leggermente differenti.

collect aka map

Data una collection crea un’altra collection con lo stesso numero di elementi, ma alterando ogni elemento per mezzo del blocco associato.

numeri = [1,2,3,4,5]
doppi = numeri.collect { |x| x*2 }

produce [2,4,6,8,10]

select aka find_all

Data una collection crea un’altra collection contenente i valori per i quali il blocco associato ritorna true

singolo = [1,2,3,4,5]
pari = singolo.select { |x|  x % 2 == 0 }

reject

Data una collection crea un’altra collection contenente i valori per i quali il blocco associato ritorna false

singolo = [1,2,3,4,5]
dispari = singolo.reject { |x|  x % 2 == 0 }

inject aka reduce

Questo è più complicato: inject diversamente dagli altri iteratori non ritorna una collection ma semplicemente un valore, che è il risultato dell’esecuzione del blocco su tutti gli elementi della collection, accumulando i valori intermedi in un’altra variabile.

 

valori = [1,2,3,4,5]
somma = valori.select { |t, x|  t + x }

Notiamo che nel blocco il costrutto |t, x| definisce due variabili: la prima è l’accumulatore, la seconda è il valore dell’elemento della collection su cui stiamo iterando.

E’ come se avessimo scritto

t=0
for x in valori do
   t = t + x
end

Questo iteratore esiste in diverse varianti, la forma più generica è:

inject( valore_iniziale) { | accumulatore, elemento | ...... }

In cui passiamo al metodo inject un argomento che rappresenta il valore iniziale della variabile di accumulo.

Il blocco è opzionale, possiamo passare come argomento anche un simbolo che rappresenta l’operazione da eseguire da ogni iterazione:

somma = valori.inject( :+, 0)

se poi il valore iniziale dell’accumulatore è 0 anche questo può essere omesso:

somma = valori.inject( :+ )

l’iteratore è così smart che è in grado di determinare che l’elemento neutro per la somma è 0 mentre quello per il prodotto è 1.

 

per ora è tutto, restate collegati!

 

Ruby 2.1: il nuovo Garbage Collector

La versione 2.1 di Ruby introduce un nuovo Garbage Collector, vediamo come funziona!

Come tutti sapete, l’azione del GC è divisa in due fasi:

  1. la fase di Mark, in cui viene esplorato dalla radice l’albero degli oggetti e viene settato il bit FL_MARK per indicare quelli “vivi”
  2. la fase di Sweep, in cui si itera sugli slot dell’heap e gli oggetti con il flag FL_MARK non settato vengono aggiunti alla lista degli oggetti disponibili (per il riutilizzo).

Durante le fasi di Mark e di Sweep, il mondo si ferma e la nostra applicazione Ruby si congela.

Con Ruby 1.8, ad intervalli prestabiliti vengono eseguite in sequenza le due fasi e questo determina un tangibile congelamento dell’applicazione a causa della durata combinata di queste due fasi.

Dalla versione 1.9.3 di Ruby la fase di Sweep anzichè essere eseguita subito dopo quella di Mark, viene suddivisa in microfasi che sono eseguite ogni volta che è richiesta l’allocazione di un nuovo oggetti. In questo modo il tempo necessario a svolgere la fase di Sweep “scompare” dalla nostra percezione, ma rimane quello necessario alla fase di Mark.

Con Ruby 2.0 è stato introdotta la Bitmap Marking GC.
Dietro questo curioso nome si nasconde una intelligente trovata di Narihiro Nakamura: tutti sapete cos’è l’ottimizzazione Copy On Write del sistema di gestione della memoria dei sistemi Linux e Unix based; i processi che vengono forkati (per esempio per gestire più richieste contemporaneamente in un server WEB) mantengono in comune oggetti in memoria fino al momento in cui uno dei processi va ad alterare l’oggetto. Questo consente di minimizzare l’utilizzo di memoria, ma nel momento in cui la fase di Mark altera il bit FL_MARK, questo fa  venire meno la suddetta condizione e quindi l’ottimizzazione COW fallisce (limitatamente agli oggetti allocati dalla nostra applicazione Ruby). L’idea di Narihiro Nakamura è quella di spostare il bit FL_MARK in una sottostruttura (una bitmap) che diventa la sola parte che viene “sporcata” nella fase di Mark.

In Ruby 2.1 è stato introdotto un nuovo GC: questo è chiamato RGENGC (Restricted Generational GC), un GC generazionale parte dal presupposto che la maggior parte degli oggetti vengono allocati e poi “muoiono giovani”, il GC distingue tra oggetti “giovani” ed oggetti “vecchi”: gli oggetti “vecchi” sono quelli che “sopravvivono” all’n-esimo GC.

Con l’RGENGC vengono effettuati due distinti GC, il Minor GC in cui vengono trattati gli oggetti “giovani” e il Major GC (che viene eseguito solo quando la memoria scarseggia) in cui vengono trattati entrambi.

(segue)