Set e Get

Sonic Pi ha un archivio globale di memoria chiamato Time State. Le due cose principali che fai con questo sono set (impostare) e get (richiamare) informazioni. Immergiamoci di più…

Set

Per impostare informazioni nel Time State abbiamo bisogno di due cose:

  1. le informazioni che vogliamo impostare,
  2. un nome unico (la chiave) per le informazioni.

Per esempio, forse vogliamo impostare il numero 3000 sotto la chiave :intensity. Questo è possibile utilizzano la funzione set:

set :intensity, 3000

Possiamo usare qualsiasi nome per la chiave. Se si sono già impostate informazioni con quella chiave, il nuovo set le sostituisce:

set :intensity, 1000
set :intensity, 3000

Nell’esempio sopra, visto che abbiamo memorizzato tutti e due i numeri sotto la stessa chiave, “vince” l’ultima chiamata di set, così il numero associato con :intensity sarà 3000 perché la prima chiamata di set è in effetti soprascritta.

Get

Per recuperare informazioni dal Time State abbiamo bisogno solamente della chiave usata per fare il set; in questo caso, :intensity. Poi, basta che chiamiamo get[:intensity], che possiamo verificare facilmente stampandone il risultato sul log:

print get[:intensity] #=> stampa 3000

Nota che le chiamate a get possono restituire informazioni che erano set da una esecuzione precedente. Una volta impostata una informazione con set, è disponibile fino a quando non viene soprascritta (come sopra abbiamo rimpiazzato il valore 1000 di :intensity con 3000) o fino a quando non viene chiuso Sonic Pi.

Thread multipli

Il beneficio principale del sistema Time State è che si può usare senza rischi attraverso thread o cicli vivi. Per esempio, puoi avere un ciclo vivo che imposta informazioni ed un altro che le recupera:

live_loop :setter do
  set :foo, rrand(70, 130)
  sleep 1
end
live_loop :getter do
  puts get[:foo]
  sleep 0.5
end

Una cosa bella dell’uso di get e set in questo modo attraverso i thread è che genera sempre lo stesso risultato ogni volta che premi “Run”. Dai, provalo. Vedi se ottieni il seguente nel tuo log:

{run: 0, time: 0.0}
 └─ 125.72265625
{run: 0, time: 0.5}
 └─ 125.72265625
{run: 0, time: 1.0}
 └─ 76.26220703125
{run: 0, time: 1.5}
 └─ 76.26220703125
{run: 0, time: 2.0}
 └─ 114.93408203125
{run: 0, time: 2.5}
 └─ 114.93408203125
{run: 0, time: 3.0}
 └─ 75.6048583984375
{run: 0, time: 3.5}
 └─ 75.6048583984375

Prova ad eseguire alcune volte — vedi, è uguale ogni volta. Questo si chiama comportamento deterministico ed è importantissimo quando vogliamo condividere la nostra musica in forma di codice e sapere che la persona che la esegue sente esattamente quello che abbiamo voluto che sentisse (come un MP3 o un flusso di internet suona lo stesso per tutti gli ascoltatori).

Un Sistema Semplice di Stato Deterministico

Nella Sezione 5.6 abbiamo parlato della ragione perché usare variabili attraverso thread può causare comportamento casuale. Questo ci blocca da potere riprodurre code come questo in maniera affidabile:

## Un Esempio di Comportamento Non-Deterministico
## (dovuto a condizioni di gara causate da vari
## cicli vivi che manipolano lo stesso variabile allo
## stesso tempo).
##  
## Se esegui questo codice noterai
## che l'elenco che viene stampato non
## è sempre in ordine!
a = (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
  a = a.shuffle
  sleep 0.5
end
live_loop :sorted do
  a = a.sort
  sleep 0.5
  puts "sorted: ", a
end

Guardiamo come possiamo fare questo con get e set:

## Un Esempio di Comportamento Deterministico
## (nonostante accesso concorrente dello
## stato condiviso) usando il nuovo sistema
## Time State di Sonic Pi.
##
## Quando questo codice si esegue, l'elenco che
## viene stampato è sempre in ordine!
##
set :a, (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
  set :a, get[:a].shuffle
  sleep 0.5
end
live_loop :sorted do
  set :a, get[:a].sort
  sleep 0.5
  puts "sorted: ", get[:a]
end

Nota che questo codice è quasi uguale alla versione prima che usava un variabile. Ma quando esegui questo codice, si comporta come si aspetta con qualsiasi codice tipico di Sonic Pi — fa la stessa cosa ogni volta in questo caso, grazie al sistema Time State.

Dunque, quando si condividono informazioni fra cicli vivi e thread, usa get e set invece di variabili per avere comportamento deterministico e riproducibile.