Set y Get

Sonic Pi tiene un almacén de memoria global llamado Time State. Las dos cosas principales que se hacen con él son set (establecer) información y get (obtener) información. Vamos a profundizar…

Set

Para almacenar información en el Time State necesitamos dos cosas:

  1. los datos que queremos almacenar,
  2. un nombre único (clave) para los datos.

Por ejemplo, puede ser que queremos almacenar el número 3000 con la clave :intensity. Eso es posible utilizando la función set:

set :intensity, 3000

Podemos utilizar cualquier nombre para nuestra clave. Si esta clave ya tiene datos almacenados, nuestro nuevo set tendrá primacía:

set :intensity, 1000
set :intensity, 3000

En el ejemplo anterior, como almacenamos ambos números bajo la misma clave, la última llamada a set ‘gana’, por lo que el número asociado a :intensidad será 3000 ya que la primera llamada a set es efectivamente anulada.

Get

Para obtener la información del Time State sólo necesitamos la clave que utilizamos para set (establecerlo), que en nuestro caso es :intensity. Entonces sólo tenemos que llamar a get[:intensity] que podemos ver imprimiendo el resultado en el registro:

print get[:intensity] #=> imprime 3000

Observa que las llamadas a get pueden devolver información que fue set en una ejecución anterior. Una vez que una pieza de información ha sido “fijada”, está disponible hasta que la información sea sobrescrita (al igual que el valor de :intensity de 1000 a 3000) o Sonic Pi se cierra.

Hilos

La principal ventaja del sistema Time State es que puede utilizarse de forma segura entre hilos o bucles vivos. Por ejemplo, puedes tener un bucle vivo estableciendo información y otro obteniéndola:

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

Lo bueno de usar get y set entre hilos de esta manera es que siempre va a producir el mismo resultado cada vez que ejecutas el código. Adelante, intentalo. Verás lo siguiente en tu bitácora:

{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

Intenta correrlo unas cuantas veces - ¿Lo ves? Es el mismo resultado cada vez. Esto es lo que llamamos comportamiento determinista y es bastante importante cuando compartimos nuesta música como código y saber que la persona que está ejecutando el código está escuchando exactamente lo que quisimos que escuchara (justo como cuando reproducimos un MP3 o una transmisión por internet, todos los oyentes escuchan lo mismo).

Un Sistema de Estados Determinista Simple

Ya en la Sección 5.6 discutimos por qué el uso de variables entre hilos puede conducir a un comportamiento aleatorio. Esto nos impide poder reproducir de manera fiable un código como este:

## An Example of Non-Deterministic Behaviour
## (due to race conditions caused by multiple
## live loops manipulating the same variable
## at the same time).
##  
## If you run this code you'll notice
## that the list that's printed is
## not always sorted!
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

Echemos un vistazo a cómo se vería esto usando get y set:

## An Example of Deterministic Behaviour
## (despite concurrent access of shared state)
## using Sonic Pi's new Time State system.
##
## When this code is executed, the list that's
## printed is always sorted!
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 como este código es casi identico a la versión donde se utiliza una variable antes de. Sin embargo cuando corres el código, se comporta como esperarías de cualquier código típico de Sonic Pi -hace exactamente lo mismo cada vez- en este caso gracias al sistema de Time State.

Siendo así, cuando compartimos información entre live loops e hilos, es preferible usar get y set en vez de variables para un comportamiento determinista y reproducible.