# Set und Get

Sonic Pi hat einen global Speicherbereich, der “Time State” genannt wird. Die beiden wesentliche Dinge, die man auf ihn an anwendet sind das Setzen von Informationen (Set) und das Holen von Information (Get).

## Set

Um Informationen innerhalb des Time States zu speichern, benötigen wir zwei Dinge:

1. die Information, die wir speichern möchten,
2. einen eindeutigen Namen (Schlüssel) für die Information.

Wir möchten beispielsweise die Zahl `3000` unter dem Schlüsselnamen `:intensity` speichern. Dies können wir mit der `set` function erreichen:

    set :intensity, 3000

Für den Schlüssel können wir jeden Namen verwenden, den wir möchten. Haben wir einmal einen Wert unter diesem Schlüsselnamen gespeichert, wird ein neuer `set` -Befehl diesen überschreiben:

    set :intensity, 1000
    set :intensity, 3000

In dem obigen Beispiel haben wir beide Werte unter dem gleichen Schlüssel abgespeichert. Der letzte Befehl ‘gewinnt’, so dass die Zahl, die mit `:intensity` assoziert ist, die `3000` sein wird und somit die erste (1000) damit überschrieben wurde.

## Get (Abfragen des Werts)

Um Informationen aus dem Time-State wieder zu holen, benötigen wir nun unseren Schlüssel, den wir bei `set` verwendet haben, also in diesem Fall `:intensity`. We müssen jetzt einfach `get[:intensity]` aufrufen und bekommen dies im log angezeigt:

    print get[:intensity]  #=> prints 3000

Achte darauf, dass Aufrufe von `get` Informationen zurückgeben kann, die bei einem vorherigem Programm-Lauf gesetzt wurden. Wurde eine Information einmal mit Hilfe von `set` gespeichert, ist sie solange verfügbar bis sie entweder überschrieben wird (wie oben die `1000` mit `3000`) oder Sonic Pi beendet wird.

## Mehrere Threads

Der wesentliche Vorteil des Time State Systems ist, dass man auf sichere Art und Weise Informationen zwischen Threads und live-loops austauschen kann. Beispielsweise könnte eine live-loop Informationen bereitstellen, die die andere live-loop ausliest:

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

Das Schöne an `get` und `set` bei Threads ist, dass sie immer das gleiche Ergebnis produzieren, wenn das Programm erneut gestartet wird. Versuch’s einfach mal selbst und prüfe nach, ob die folgende Ausgabe im Log erscheint:

    {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

Starte das Programm einfach mal mehrere Male - du wirst sehen, dass das Ergebnis immer das Gleiche ist. Das bezeichnen wir als “deterministisches” Verhalten und das ist sehr wichtig, wenn wir unsere Musik an andere weitergeben möchten und sicher sein wollen, dass die Person, die die Musik anhört, genau das gleiche Ergebnis hören wird wie wir, die es erstellt haben (ähnlich wie das Spielen einer MP3 oder das Streamen von Musik).

## Ein einfaches deterministisches State System

In Abschnitt 5.6 haben wir gezeigt, wie die Nutzung von Variablen in verschiedenen Threads zu zufälligen Resultaten führen kann. Das verhindert wiederum die sichere Reproduktion von bestimmten Code wie diesem:

    ## Ein Beispiel für ein nicht-deterministisches Verhalten
    ## (aufgrund von Race Conditions, die durch
    ## mehrfache live-loops ausgelöst werden, die auf
    ## gleiche Variable zugreifen).
    ##
    ## Wenn Du den Code startest, siehst Du,
    ## dass die Liste nicht immer sortiert ist.
    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

Schauen wir mal, wie wir `get` und `set` einsetzen können:

    ## Ein Beispiel für ein deterministisches Verhalten
    ## (trotz des gleichzeitigen Zugriff auf einen gemeinsamen Zustand)
    ## mit Hilfe des Sonic Pi Time State Systems
    ##
    ## Wenn dieser Code gestartet wird,
    ## wird die Liste immer sortiert ausgegeben.
    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

Beachte, dass dieser Code fast identisch zu dem Code ist, der die Variable zum Teilen der Information verwendet hat. Allerdings verhält er sich so, wie man es sich bei einem typischen Sonic Pi Code erwartet - er verhält sich immer gleich in diesem Fall dank des Time State Systems.

Deshalb verwende immer `get` und `set`, wenn Du Daten zwischen live-loops und Threads teilen möchtest anstatt Variablen zu verwenden.