10.1 Set and Get

# Set and Get

Sonic Pi has a global memory store called Time State. The two main
things you do with it are to `set` information and `get`
information. Let's dive deeper...

## Set

To store information into the Time State we need two things:

1. the information we want to store,
2. a unique name (key) for the information.

For example, we might want to store the number `3000` with the key
`:intensity`. This is possible using the `set` function:

```
set :intensity, 3000
```

We can use any name for our key. If information has already been stored
with that key, our new `set` will override it:

```
set :intensity, 1000
set :intensity, 3000
```

In the above example, as we stored both numbers under the same key, the
last call to `set` 'wins', so the number associated with `:intensity`
will be `3000` as the first call to `set` is effectively overridden.

## Get

To fetch information from the Time State we just need the key we used to
`set` it, which in our case is `:intensity`. We then just need to call
`get[:intensity]` which we can see by printing out the result to the
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.

## Multiple 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

Back in Section 5.6 we discussed why using variables across threads can
lead to random behaviour. This stops us from being able to reliably
reproduce code such as this:

```
## 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
```

Let's take a look at how this might look using `get` and `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.
