Suppose you found an envelope lying on the street and on the front of the envelope was printed the name numberOfDog'sTeeth. Suppose further that you opened the envelope and inside was a piece of paper with the number 42 written upon it. What might you conclude from such an encounter? Now suppose you kept walking and found another envelope labeled meaningOfLifeUniverseEverything and, again, upon opening it you found a slip of paper with the number 42 on it. Further down the road, you find two more envelopes, entitled numberOfDotsOnPairOfDice and StatuteOfLibertyArmLength, both of which contain the number 42.
Finally, you find one last envelope labeled sixTimesNine and inside you, yet again, find the number 42. At this point, you're probably thinking 'somebody has an odd affection for the number 42' but then the times table that is stuck somewhere in the dim recesses of your brain begins yelling at you saying '54! It's 54!'. After this goes on for an embarrassingly long time, you realize that 6 * 9 is not 42, but 54. So you cross out the 42 in the last envelope and write 54 instead and put the envelope back where you found it.
This strange little story, believe it or not, has profound implications for writing programs that both humans and computers can understand. For programming languages, the envelope is a metaphor for something called a variable, which can be thought of as a label for a place in memory where a primitive value can reside. In many programming languages, one can change the value at that memory location, much like replacing the contents of an envelope. A variable is our first encounter with a concept known as abstraction, a concept that is fundamental to the whole of computer science.
Most likely, you've encountered the term variable before. Consider the slope-intercept form of an algebraic equation of a particular line:
You probably can tell from this equation that the slope of this line is 2 and that it intercepts the y-axis at -3. But what role do the letters y and x actually play? The names x and y are placeholders and stand for the x- and y-coordinates of any conceivable point on that line. Without placeholders, the line would have to be described by listing every point on the line. Since there are an infinite number of points, clearly an exhaustive list is not feasible. As you learned in your algebra class, the common name for a place holder for a specific value is the term variable.
One can generalize the above line resulting in an equation that describes every line.
Here, the variable m stands for the slope and b stands for the y-intercept. Clearly, this equation was not dreamed up by a computer scientist since a cardinal rule is to choose good names for variables, such as s for slope and i for intercept. But alas, for historical reasons, we are stuck with m and b.
The term variable is also used in most programming languages, including Sway, and the term has roughly the equivalent meaning. The difference is programming languages use the envelope metaphor while algebra does not (the difference is purely philosophical and not worth going into at this time). Suppose you found three envelopes, marked m, x, and b, and inside those three envelopes you found the numbers 6, 9, and -12 respectively. If you were asked to make a y envelope, what number should you put inside? If the number 42 in the sixTimesNine envelope in the previous story did not bother you (e.g., your internal times table was nowhere to be found), perhaps you might need a little help in completing your task. We can have Sway calculate this number with the following dialog:
sway> var m = 6; INTEGER: 6 sway> var x = 9; INTEGER: 9 sway> var b = -12; INTEGER: -12 sway> var y = m * x + b; INTEGER: 42 sway> y; INTEGER: 42
One creates variables in Sway with the var keyword.
The creation of a variable is known as a declaration or definition. In Sway, the token after the keyword var is the variable being defined and the value after the equals sign is the initial value of the variable. The last definition shows that the initial value can be an expression which refers to other variables. The Sway interpreter, when asked to compute the value of an expression containing variables, goes to those envelopes (so to speak) and retrieves the values stored there. Note also that Sway requires the use of the multiplication sign to multiply the slope m by the x value. In the algebraic equation, the multiplication sign is elided, but is required here.
Here are some more examples of variable creation using the var keyword:
sway> var dots = 42; INTEGER: 42
This interaction defines a variable named dots whose value is bound to the number 42. The response of the interpreter to a variable declaration is to display the value bound to the variable.
sway> var bones = 206; INTEGER: 206
sway> dots; INTEGER: 42
sway> bones; INTEGER: 206
sway> var CLXIV = bones - dots; INTEGER: 164
After the declaration of variable, the variable and its value can be used interchangeably. Thus, one use of variables is to set up constants that will be used over and over again. For example, it is an easy matter to set up an equivalence between the variable PI and the real number 3.14159.
var PI = 3.14159; var radius = 10; var area = PI * radius * radius; var circumference = 2 * PI * radius;
Notice how the expressions used to compute the values of the variables area and circumference are more readable than if 3.14159 was used instead of PI. In fact, that is one of the main uses of variables, to make code more readable. The second is if the value of PI should change (e.g. a more accurate value of PI is desired, we would only need to change the definition of PI (this assumes, of course, we can store those definitions for later retrieval and do not need to type them into the interpreter again).
The variables and their values are stored in a structure called an environment. You can think of an environment as shoebox full of envelopes. When we define a variable, we put a new envelope, with the name of the variable on the outside, at the front of the box. Inside each envelope is the initialization value of the variable. When we need the value of a variable, we start looking in the shoebox, from front to back, looking for the right envelope. When we find the properly labeled envelope, we retrieve the value inside the envelope.
The environment is said to hold variables and their bindings (i.e., the values in the envelopes). A variable is said to be bound with respect to an environment if it has a binding in that environment. When asked to evaluate a variable, Sway simply looks up the variable in the environment and retrieves its value. Sometimes, the value bound to a variable is another environment. In fact, there is a variable named this that is that holds the location of the current environment (the this variable is predefined so you do not need to define it yourself). If you wish to see what bindings are in effect, you can ask the interpreter by issuing the command
If we do so after defining all the variables above, we get the following response from the interpreter:
sway> pp(this); <OBJECT 1651>: context: <OBJECT 323> dynamicContext: null this: <OBJECT 1651> constructor: null dots: 42 bones: 206 CLXIV: 164 PI: 3.141590 radius: 10 area: 314.159000 circumference: 62.831800 OBJECT: <OBJECT 1651>
Issuing the pp command is, in programming language parlance, an example of 'calling a function' and 'passing an argument'. We will learn more about functions later, but the main idea is that a function performs some useful task or set of tasks. In this case, the task is to show the current set of variable - value pairs.
In addition to the bindings of the variables we previously defined, we see some additional bindings for constructor, dynamicContext, context, and this. These variables are predefined by Sway for every environment. In this particular case, the variable context is bound to the environment that has the Sway built-in functions defined. As you will later see, sometimes we will try to look up a variable in the current environment. If we don't find it, we will look up the value of the context variable instead and continue our search using that environment instead. We will discuss the other predefined variables further at a later time.
If you were to ask the interpreter to display the bindings of context, you would get a long list:
sway> pp(context); <OBJECT 137>: array?: <function array?(a)> string?: <function string?(a)> real?: <function real?(a)> integer?: <function integer?(a)> ... +: <function +(a,b)> -: <function -(a,b)> *: <function *(a,b)> /: <function /(a,b)> ... if: <function if(a,$b,$c)> while: <function while($a,$b)> ... ||: <function ||> &&: <function &&> ... catch: <function catch($a)> =: <function =($a,b)> .: <function .(a,$b)> ... OBJECT: <OBJECT 137>
Note that even though the variables context and this are bound to environments, the pp function says they are bound to objects. In Sway, unlike other languages, objects and environments are the same thing. In fact, the terms object and environment should all be considered equivalent. You will learn more about objects in a later chapter.
After displaying the bindings, the interpreter displays the result of evaluating the pp command, which is always the thing passed to the pp function. The fact that something was displayed other than the returned value is known as a side-effect. The side-effect is not part of the value of the expression. It is these very side-effects that make it dangerous to depend on the order of operand evaluation.
The ability to look at the current set of bindings is a useful tool for figuring out why a program is not behaving as you think it should. The process of fixing such problems is known as debugging.
Unlike many languages, Sway is quite liberal in regards to legal variable names and to what entities variables can be bound. Consider the following variable declarations:
sway> var times = *; BUILT-IN: <function *> sway> 6 times 7; INTEGER: 42 sway> var dots+bones = 5; INTEGER: 5 sway> dots+bones; INTEGER: 5 sway> dots + bones; INTEGER: 248
The first declaration defines a variable named times and gives it the same value as the operator *. Note that the response of the interpreter tells us that times has been bound to the function originally bound to *. At this point, both the variables times and * are bound to the same function and can be used interchangeably, as the next interaction shows. From this example, we can see that operators are regular variables which happen to be bound to appropriate built-in functions. As stated earlier, this allows the Sway programmer great latitude in creating new operators. From the next interactions, we can see that whitespace is very important in delineating variable names: dots+bones is a single variable name while dots + bones is a combination of two distinct variables named dots and bones; in particular they are combined with the built-in function bound to the variable +.
Variables are the next layer in a programming languages, resting on the primitive expressions and combinations of expressions (which are expressions themselves). In fact, variables can be thought of as an abstraction of the primitives. As an analogy, consider your name. Your name is not you, but it is a convenient (and abstract) way of referring to you. In the same way, variables can be thought of the names of things. They aren't the thing itself, but a convenient way to referring to the thing.
While Sway lets you name variables in wild ways, you should temper your creativity if it gets out of hand. For example, rather than use the variable m for the slope, we could use the name slope instead:
var slope = 6;
We could have also used a different name:
var !@#$% = 6;
The name !@#$% is a perfectly good variable name from Sway's point of view. It is a particularly poor name from the point of making your Sway programs readable by you and others. It is important that your variable names reflect their purpose. In the example above, which is the better name: m, slope, or !@#$%?
- Languages that do not allow changes to a variable are called functional languages. Sway is an 'impure' functional language since it mostly functional but allows variable modification.
- Another fundamental concept is analogy and if you understand the purpose of the envelope story after reading this section, you're well on your way to being a computer scientist!
- The third great fundamental concept in computer science is generalization. In particular, computer scientists are always trying to make things more abstract and more general (but not overly so). The reason is that software/systems/models exhibiting the proper levels of abstraction and generalization are much much easier to understand and modify. This is especially useful when you are required to make a last second change to the software/system/model.
- A keyword is a token that cannot be used as the name of a variable. Compared to most languages, Sway has surprisingly few keywords. In fact, there are just three: var, function, and else. The remaining keywords will be discussed the others in subsequent sections.
- The believed value of PI has changed throughout the centuries and not always to be more accurate (see [[w:History of Pi|]])
- In Sway, all operators are functions. Conversely, all functions that take two arguments are operators. More on this later.