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

The nice thing about using get and set across threads like this is that it will always produce the same result every time you hit run. Go on, try it. See if you get the following in your 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

Try running it a few times - see, it’s the same every time. This is what we call deterministic behaviour and it’s really very important when we want to share our music as code and know that the person playing the code is hearing exactly what we wanted them to hear (just like playing an MP3 or internet stream sounds the same for all listeners).

A Simple Deterministic State System

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

Notice how this code is pretty much identical to the version using a variable before it. However when you run the code, it behaves as you would expect with any typical Sonic Pi code - it does the same thing every time in this case thanks to the Time State system.

Therefore, when sharing information across live loops and threads, use get and set instead of variables for deterministic, reproducible behaviour.