“Variables” are a fundamental concept in programming. They provide a way to refer to a value, even if the value is not known. For example, if we have some apples, but we don’t know how many apples, we can refer to “the apples” without knowing how many. If we have 5 apples, then “the number of apples” (a numeric value) is “5”. Variables provide a convenient way to store values, and to pass values from one part of a program to another. The value held by the variable is not fixed, it can be changed (hence the name “variable”).
A variable can be thought of as a named container that holds data.
Example
Let’s say that we have some apples, we are then given 3 more apples, and we give 2 apples away. Our programming task is to write a program that calculates the number of apples that we end up with.
Since I didn’t specify how many apples we started with, we will use a variable to represent the apples, and give the variable the name “apples”. To run the program, we will just need to enter the initial value of “apples”, and the program will return the number of apples that we end up with.
This task may be broken down into the following steps:
- Set initial value of “apples” (how many apples do we start with?)
- Add 3 to the value of “apples” (the 3 additional apples that we are given)
- Take away 2 from the value of “apples” (the two apples that we give away)
- The value of “apples” is now the number of apples that we have left.
In pseudo-code, assuming that we start with 7 apples:
1 2 3 4 5 |
SET apples 7 apples = apples + 3 apples = apples - 2 RETURN apples |
In Nyquist code, this could be written as:
1 2 3 4 5 |
(setf apples 7) (setf apples (+ apples 3)) (setf apples (- apples 2)) apples |
- The first line uses the command “SETF” to set the value of the variable “apples” to integer 7.
“apples” is the name of the variable, and its value is 7. - The second line nests two commands: SETF and “+” (addition).
- The inner operation (addition) is performed first,
then 3 is added to the value of “apples”. - The outer command (SETF) sets the value of “apples” to the result of the addition.
“apples” now has a value of 10.
- The inner operation (addition) is performed first,
- The third line again nests one command inside another:
- The inner operation (subtraction) is performed first,
then 2 is subtracted from the value of “apples”. - The outer command (SETF) sets the value of “apples” to the result of the subtraction.
“apples” now has a value of 8.
- The inner operation (subtraction) is performed first,
- The final line evaluates to 8, which is our return value.
Strictly speaking the last line of our Nyquist code is not required, because the previous line already evaluates to 8. A better way to write the Nyquist code would be:
1 2 3 4 |
(setf apples 7) (setf apples (+ apples 3)) (- apples 2) |
Unlike some other languages, it is not necessary to declare a variable before use. Nyquist variables come into existence automatically as soon as a variable name is given a value.
Do try the Nyquist examples in the Nyquist Prompt, and experiment using different values.
Inputting numeric values
Clearly it would be better if we could input the initial value of “apples” rather than having to modify the code for different initial values. Audacity allows us to do this by using a special “widget” command. More about widgets later, but for now here’s an example of an “int” (integer) widget for setting a variable to an integer (whole number) value:
- ;control
This tells Audacity that we require a “widget”.
Nyquist ignores lines that begin with a semicolon, which is what we want because this line is for Audacity, not directly for Nyquist. - apples
The name of the variable that we want to set. - “Initial number of apples”
This text is displayed to the left of the widget. - int
This tells Audacity to provide a slider widget for integer values. - “0 to 100”
This text is displayed to the right of the widget. It’s more common for this to be an empty string, which is written as two double quotes: “”. - 7 0 100
These three numbers tell Audacity:- The default value (7)
- The minimum value (0)
- The maximum value (100)
Now that we have an input control, our code can be written as:
1 2 3 4 |
;control apples "Initial number of apples" int "0 to 100" 7 0 100 (setf apples (+ apples 3)) (- apples 2) |
When you run the code in the Nyquist prompt, you should see a dialogue screen appear similar to this:
Data Types
Numeric data
So far we have only used values that are whole numbers (integers). Nyquist also supports decimal fractions, which are called “floats” (an abbreviation of “floating point number“). Floating point numbers in Nyquist are accurate to around 14 decimal places.
1 2 |
;control variable-name "text-left" int "text-right" initial-value minimum maximum |
1 2 |
;control variable-name "text-left" float "text-right" initial-value minimum maximum |
Text data
Text values are called “strings” (a string of characters). Like numeric values, a variable can be assigned a string value. For example:
1 2 3 |
(setf my-string-variable "Hello World") (print my-string-variable) |
Strings may be input via a “string widget”:
1 2 |
;control variable-name "text-left" string "text-right" "default-string" |
Lists
Lists are a very important data type in Nyquist, and will be the subject of a future tutorial, but for now here is a basic example to set a variable to a list value, and print the second item in the list.
1 2 3 |
(setf my-variable (list 2 4 6 8)) (print (second my-variable)) |
Lists are not confined to lists of numbers, they can contain any type of data, including integers, floats, string, other lists, …
1 2 3 |
(setf my-variable (list 3.142 "hello world" 42)) (print (second my-variable)) |
Bool (boolean values)
Boolean values are the values “true and false”. In Nyquist, a boolean “true” value is represented by the symbol “t”. Nyquist is not case sensitive, so either an upper-case “T” or a lower-case “t” may be used. By convention a lower-case “t” is preferred. Boolean “false” is represented by the symbol “NIL”. In documentation this is usually written as upper-case “NIL” (as are most Nyquist keywords), but usually as lower-case “nil” in code.
Boolean values are frequently used in conditional branching. As a general rule, anything that does not evaluate to NIL will evaluate to Boolean T. The following examples all print “True”:
1 2 3 4 5 |
(setf my-var t) (if my-var (print "True") (print "False")) |
1 2 3 4 5 |
(setf my-var 42) (if my-var (print "True") (print "False")) |
1 2 3 4 5 |
(setf my-var "Hello World") (if my-var (print "True") (print "False")) |
These examples print “False”:
1 2 3 4 5 |
(setf my-var nil) (if my-var (print "True") (print "False")) |
1 2 3 4 5 |
(setf my-var (= 42 17)) (if my-var (print "True") (print "False")) |
Note that in Nyquist, variables do not have a fixed data type. The type of data stored in a variable may be changed at any time (though it may not always be wise to do so. It is therefore good practice to give variables descriptive names so as to avoid confusion. For example, a variable called “counter” can reasonably be expected to have an integer value, whereas “track-name” suggests a string value.
Other data types that will be covered in later tutorials include:
- sounds
In Nyquist, a “sound” is a distinct data type. Sounds can be created, passed as parameters, printed, and set to variables just like strings, numbers, and other data types. - arrays
A data type that represents an indexed collection of elements. - characters (“Chars”)
A single character data type. Note that a char can be converted to a string, and a string can be converted to chars, but strings and characters are not the same, they are different data types. - symbols
Unique strings that serve as names of variables and names of functions. - objects
May be built-in objects or user defined. - streams
A sequence of data elements. - subrs
Built-in functions - fsubrs
Special forms - closures
User defined functions
Wrapping up
In this tutorial we have learned what variables are, and how to set the value of a variable. We have looked at a few of the “widgets” provided by Audacity for inputting values, and introduced data types supported by Nyquist.
In future tutorials we shall look at some of Nyquist’s built-in functions for working with different types of data, including many of Nyquist’s built-in functions for manipulating sound.