# Variabili

Una cosa che può risultarti utile è quella di creare nomi da assegnare alle cose. Sonic Pi rende questo processo molto semplice: basta che scrivi il nome desiderato, il segno uguale (‘=’), e dopo la cosa che vuoi ricordarti:

    sample_name = :loop_amen

Nell’esempio sopra ci siamo ‘ricordati’ il simbolo ‘:loop_amen’ grazie alla variabile ‘sample_name’. Adesso, possiamo utilizzare ‘sample_name’ ovunque avremmo usato ‘:loop_amen’. Ecco un esempio:

    sample_name = :loop_amen
    sample sample_name

Ci sono tre ragioni principali che rendono utile l’impiego di variabili in Sonic_Pi: comunicare significati, organizzare le ripetizioni e catturare i risultati delle cose.

## Comunicare i significati

Quando programmi è facile pensare semplicemente che stai dicendo al computer come fare qualcosa. E finché il computer capisce, va tutto bene! Tuttavia, è importante tenere a mente che non solo il computer legge il codice,ma anche altre persone potrebbero farlo per capire cosa sta succedendo. Inoltre, è probabile che tu stesso/a andrai prima o poi a rileggere il tuo codice e cercare di capire a che cosa serve. Anche se adesso qualche passaggio ti sembra ovvio, potrebbe non esserlo per qualcun altro o per te stesso/a nel futuro!

Un modo per aiutare gli altri a comprendere il tuo programma è scrivere commenti (come abbiamo visto nella sezione precedente. Un altro modo è usare dei nomi di variabili che abbiano un significato. Per esempio, guarda il codice seguente:

    sleep 1.7533

Perché in questo codice è scritto il numero ‘1,7533’? Da dove salta fuori? Che cosa significa? Guarda invece questo codice:

    loop_amen_duration = 1.7533
    sleep loop_amen_duration

Adesso è molto più chiaro a cosa si riferisce ‘1,7533’:è la durata del campione ‘:loop_amen’! Adesso, potresti domandarti perché non scrivere semplicemente:

    sleep sample_duration(:loop_amen)

Questa è certamente un modo molto semplice e carino di comunicare lo scopo di un codice.

## Gestire le ripetizioni

Spesso può succedere che nel codice ci siano molte ripetizioni e quando vuoi cambiare qualcosa, è necessario farlo in molti punti. Guarda questo esempio:

    sample :loop_amen
    sleep sample_duration(:loop_amen)
    sample :loop_amen, rate: 0.5
    sleep sample_duration(:loop_amen, rate: 0.5)
    sample :loop_amen
    sleep sample_duration(:loop_amen)

Facciamo un sacco di cose con `:loop_amen`! E se volessimo sentire la stessa cosa ma con un loop diverso come, ad esempio, `:loop_garzul`? Saremmo costretti a trovare e rimpiazzare tutti i `:loop_amen`con `:loop_garzul`. Potresti farlo se avessi a disposizione molto tempo ma se ti stai esibendo su un palco? Spesso non hai il lusso di avere molto tempo, specialmente se non vuoi che la gente smetta di ballare.

E se avessimo scritto il codice in questo modo:

    sample_name = :loop_amen
    sample sample_name
    sleep sample_duration(sample_name)
    sample sample_name, rate: 0.5
    sleep sample_duration(sample_name, rate: 0.5)
    sample sample_name
    sleep sample_duration(sample_name)

Questo codice fa esattamente la stessa cosa di quello di prima (prova) ma ci dà la possibilità di cambiare una riga di codice `sample_name = :loop_amen` in `sample_name = :loop_garzul` e, grazie a questa variabile magica, verrà cambiato dappertutto.

## Catturare i risultati

Un buon motivo per utilizzare le variabili è la possibilità di catturare i risultati delle cose. Per esempio, magari vuoi provare a lavorare con la durata di un sample:

    sd = sample_duration(:loop_amen)

Ora possiamo usare `sd` in ogni punto dove abbiamo bisogno della durata del camptione `:loop_amen`.

Un risultato ancora più importante, forse, è che una variabile ci permette di catturare il risultato quando chiamiamo `play` o `sample`:

    s = play 50, release: 8

Ora che abbiamo catturato `s` come variabile, possiamo controllare il sintetizzatore mentre sta funzionando:

    s = play 50, release: 8
    sleep 2
    control s, note: 62

Vedremo come controllare i sintetizzatori in modo più dettagliato più tardi in questa sezione.

## Attenzione: Variabili e Thread

Mentre le variabili sono ottime per assegnare nomi alle cose ed acquisire i relativi risultati, è importante sapere che dovrebbero essere generalmente usate in locale all’interno di un thread. Per esempio, non fare questo:

    a = (ring 6, 5, 4, 3, 2, 1)
    live_loop :sorted do
      a = a.sort
      sleep 0.5
      puts "sorted: ", a
    end
    live_loop :shuffled do
      a = a.shuffle
      sleep 0.5
    end

Nell’esempio di sopra, assegniamo un cerchio di numeri a un variabile `a` e poi l’usiamo in due `live_loop` (cicli dinamici) diversi. Nel primo `live_loop`, ogni `0.5` secondi, ordiniamo il cerchio (a `(ring 1,2,3,4,5,6)`) e lo stampiamo sul log. Se esegui il codice, trovi che l’elenco stampato non è sempre ordinato!. Questo forse ti sorprenderà — specialmente che a volte l’elenco viene stampato in ordine e a volte no. Questo si chiama comportamento “non-deterministico” ed è il risultato di un problema piuttosto difficile che si chiama “condizione di gara”. Il problema è dovuto al fatto che anche il secondo ciclo sta manipolando l’elenco (in questo caso, rimescolandolo) e al punto che l’elenco viene stampato, alcune volte è appena stato ordinato ed alcune volte è appena stato rimescolato. Entrambi i cicli fanno una gara di fare qualcosa differente con lo stesso variabile ed ogni volta “vince” un ciclo diverso.

Esistono due soluzioni a questo. Prima, non usare lo stesso variable in cicli o thread molteplici. Per esempio, il codice seguente sempre stamperà un elenco ordinato perché ogni ciclo ha un proprio variabile:

    live_loop :shuffled do
      a = (ring 6, 5, 4, 3, 2, 1)
      a = a.shuffle
      sleep 0.5
    end
    live_loop :sorted do
      a = (ring 6, 5, 4, 3, 2, 1)
      a = a.sort
      sleep 0.5
      puts "sorted: ", a
    end

Comunque, a volte vogliamo condividere cose fra diversi thread. Per esempio, la chiave attuale, BPM, sintetizzatore, ecc. In questi casi, la soluzione è usare il sistema speciale di stato “thread-safe” (sicuro per i thread) di Sonic Pi attraverso le funzioni `get` e `set`. Questo si descrive dopo, nella sezione 10.