# Переменные

Присвоение имён полезно для вашего кода. С Sonic Pi это очень просто. Вы пишете желаемое имя, знак равенства, а затем то, что нужно запомнить:

    sample_name = :loop_amen

В этом примере мы “запомнили” обозначение `:loop_amen` в переменной `sample_name`. Теперь мы можем пользоваться `sample_name` везде, где мы могли бы указать `:loop_amen`. Например:

    sample_name = :loop_amen
    sample sample_name

Есть три главных причины для использования переменных в Sonic Pi: присвоение значения, управление повторами и захват результатов операций.

## Присвоение значения

Когда вы пишете код, вы говорите компьютеру сделать что-то. Пока компьютер это понимает - всё в порядке. Но всё же важно помнить, что код читает не только компьютер. Другие люди, возможно, захотят тоже прочесть его и попробовать разобраться, что в нём происходит. Скорее всего и вы сами будете читать и пытаться понять свой собственный код в будущем. Сейчас всё кажется очевидным, но для остальных, или же для вас самих в будущем, это может быть не так!

Одним из способов помочь другим понять, что делает ваш код, - это оставлять комментарии (как мы это видели в предыдущей главе). Ещё один способ - давать осмысленные имена переменным. Посмотрите на этот код:

    sleep 1.7533

Зачем указано число `1.7533`? Откуда оно взялось? Что оно означает? Теперь взгляните на этот пример:

    loop_amen_duration = 1.7533
    sleep loop_amen_duration

Вот теперь стало ясно, что значит `1.7533`. Это же продолжительность сэмпла `:loop_amen`! Конечно, вы могли бы заметить, почему бы просто не написать так:

    sleep sample_duration(:loop_amen)

Это, безусловно, очень хороший способ выразить намерения кода.

## Управление повторами

Часто вы видите много повторений в своем коде. Когда необходимо что-то поменять, то делать это приходится во многих местах. Посмотрите на следующее:

    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)

Много чего мы делаем с `:loop_amen`! Но что если мы захотим послушать как это будет звучать с другим замкнутым сэмплом, таким как `:loop_garzul`? Пришлось бы найти и заменить все `:loop_amen` на `:loop_garzul`. Этим можно заняться, если больше нечего делать. А как насчет живого выступления? Иногда время - это непозволительная роскошь. Особенно, если вы хотите, чтобы люди продолжали танцевать.

Ну, а если бы вы записали свой код так:

    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)

Он делает совершенно то же самое (попробуйте сами). Зато тут есть возможность заменить строку `sample_name = :loop_amen` на `sample_name = :loop_garzul`, что приведёт к реальным изменениям во многих местах. Вот что даёт нам магия переменных.

## Захват результатов

Наконец, хороший повод использовать переменные - захватывать результат чего-либо. К примеру, вам может понадобится что-то сделать с продолжительностью сэмпла:

    sd = sample_duration(:loop_amen)

Теперь можно вставлять `sd` везде, где нам нужна длительность сэмпла `:loop_amen`.

Вероятно, ещё более важно то, что переменная разрешает нам сохранить результат вызова `play` или `sample`:

    s = play 50, release: 8

Мы захватили и запомнили `s` как переменную, которая позволяет управлять синтом, пока он играет:

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

В следующей главе мы рассмотрим подробнее управление синтами.

## Внимание: переменные и потоки

Хотя переменные хороши для присвоения имени и сохранения результатов, важно знать что они обычно должны использоваться в потоке. Например, не делайте так:

    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

В примере выше мы присвоили ряд чисел переменной ‘a’ и затем использовали её в двух отдельных ‘live_loop`s’. В первом живом цикле каждые ‘0,5’ секунды мы сортируем кольцевой список (1, 2, 3, 4, 5, 6), затем отображаем результат в журнале. Если ты запустишь код, ты увидишь, что выведенный список не всегда отсортирован!. Это может быть для тебя сюрпризом, ведь иногда список выводится отсортированным, а иногда нет. Это называется недетерминированным поведением и является результатом неприятной проблемы называемой гонкой состояний. Проблема заключается в том, что второй живой цикл также работает с нашим кольцевым списком (в данном случае перемешивает его) и на момент вывода на экран список может быть как отсортирован, так и перемешан. Оба живых цикла соревнуются сделать разные вещи с одной переменной и каждый раз ‘побеждает’ разный цикл.

Есть два решения. Первое: не использовать одну переменную в разных живых циклах или потоках. Например, код ниже всегда выводит отсортированный список, поскольку каждый живой цикл имеет собственную отдельную переменную:

    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

Однако, иногда мы хотим поделиться чем-то между потоками. Например, текущей тональностью, BMP, синтом и т.д. В этом случае решением будет воспользоваться специальными потоко-безопасными состояниями системы Sonic Pi через функции ‘get’ и ‘set. Это будет осуждаться в разделе 10.