Set e Get

O Sonic Pi tem um armazenamento global chamado de Time State. As duas coisas principais que fazes com ele é armazenar (set) informação e ler ( get ) informação. Vamos aprofundar…

Set

Para armazenar informação no Time State são necessárias duas coisas:

  1. a informação que queremos armazenar,
  2. uma chave (nome único) para a informação.

Por exemplo, nós podemos querer armazenar o numero 3000 com a chave :intensity. Isto é possível utilizando a função set :

set :intensity, 3000

Podemos usar qualquer nome para a nossa chave. Se alguma informação já foi armazenada anteriormente com a mesma chave, o nosso novo set vai substitui-la:

set :intensity, 1000
set :intensity, 3000

No exemplo em cima, nós guardamos ambos os números utilizando a mesma chave, a ultima chamada set ganha , por isso o numero associado a :intensity vai ser 3000 já que a primeira chamada ao set é efetivamente substituída.

Get

Para tirar informação do Time State só precisamos de utilizar a chave que utilizamos para armazena-la (set) , que no nosso caso e :intensity. Só precisamos então de chamar get[:intensity]que podemos ver ao imprimirmos o resultado para o log:

print get[:intensity] #=> prints 3000

Notice that calls to get can return information that was set in a previous run. Once a piece of information has been set it is available until either the information is overridden (just like we clobbered the :intensity value of 1000 to 3000 above) or Sonic Pi is closed.

Várias Threads

The main benefit of the Time State system is that it can be safely used across threads or live loops. For example, you could have one live loop setting information and another one getting it:

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

Atrás na secção 5.6 discutimos a razão pela qual utilizar variáveis através de diferentes threads pode levar a comportamento aleatório. Isto faz-nos desconfiar de código como este:

## Um exemplo de comportamento não-determinístico
## (devido a race conditions causadas por múltiplos
## loops manipulando a mesma variárvel ao mesmo tempo).
##  
## Se você executar este código você notará
## que a lista que é impressa
## nem sempre sai ordenada!
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

Let’s take a look at how this might look using get and set:

## Um exemplo de comportamento determinístico
## (apesar do acesso simultâneo ao estado compartilhado)
## usando o novo sistema Time State do Sonic Pi.
##
## Quando este código é executado, a lista
## sempre é impressa de forma ordenada!
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.