PencilCoder

Teacher's Guide: Variables!

Overview

This lesson introduces students to the concepts of variables and variable assignment. Variables are shown to be used for multiple purposes, including storing and modifying values (in particular while iterating using loops), documenting code, and improving readability of code.

This lesson also gives students additional practice iterating with basic for loops before moving on (in the next lesson) to "for x in" loops, i.e, loops that include an explicit index.

More about the lesson

Assignment

As in many coding languages, Coffeescript uses the equal sign, =, for assignment rather than for testing for equality. This can be a source of confusion for students, though in general they adjust fairly well to this usage. This curriculum is structured to help avoid such confusion, by delaying the introduction of comparison operators until many lessons later (in Comparison Operators!), after students are well experienced with variables and assignment.

In any event, students tend not to have much trouble accepting the role that coding languages such as Coffeescript give the equal sign. This is especially true with basic assignment statements such as x = 5. The most notable exception involves assignment statements that update a variable based on its previous value, such as x = x + 1. It may be helpful to draw attention to such "strange" statements, making explicit the fact that while in math, x = x + 1 doesn't make sense, it makes perfect sense in coding. That's because in a coding context, the expression on the right-hand side always gets evaluated first. The equal sign is processed last, causing the variable on the left to take on the resulting value on the right. Assignment always happens last.

Variable names

The Dot Art! lesson emphasized the value of choosing good names for programs. Encourage students to likewise use meaningful names for variables. For example, if coding a program to draw a spiral by using successively larger radii, the variable name radius would be much more informative and readable than x. Encourage students to follow (relatively) standard naming conventions. For example, variable names should begin with lower case letters, unless they refer to a value that should be considered a constant, in which case all caps should be used. Encourage use of camel case (e.g., myColor) or when using all caps, use of underscores to separate terms (e.g., EXAMPLE_VARNAME). Naturally, there are tradeoffs to be made. For example, when all that is needed is a simple index, letters x and y or i, j, and k are appropriate.

Notes to activities

The generalization of the algorithm for drawing a star can be tricky. The problem is that the familiar, hand-drawn, 5-pointed star algorithm only generalizes to odd-pointed stars. Use of this algorithm with even numbers of points will lead to polygons (with a number of sides equal to half the number of specified points) rather than stars. However, the algorithm for the six-pointed star, discussed in the Notes to the Line Art! lesson, generlizes to any number of points. For additional star-drawing algorithms, see Notes to the For Loops! lesson.

With the Starburst activity, students should not use a call to home. If they object, point out that an algorithm to create a starburst that involves getting back to its center using home won't be useful for creating starbursts at other locations on the visible screen. However, we'll want to do precisely that in an activity in a subsequent lesson. From this activity, students will see that variables are useful to save randomly-generated numbers that we wish to refer to more than once.

The DotSpiral and HandSpiral activities make use of what is sometimes called the accumulator pattern, which involves initializing a variable prior to the loop, and updating it on each iteration. For example, the code below produces a simple spiral:

Code for Spiral Blank space Image of Spiral

The accumulator pattern surfaces frequently in coding, so it may be worth drawing students attention to it. It also uses the x = x + 1 assignment statement, mentioned above, that tends to trip up students.

The spiral illustrations both suggest curving spirals, but this need not be the case. For example, one might also create a Squiral by using 90° turn angles, but straight sides of ever-increasing length.

Additional activities

  • WindsweptField: add additional variables to the GrassyField program to facilitate biasing the angles in a particular direction, as if the grass had been blown by a strong wind.
  • As an extention to the Starburst activity, create a Fireworks program which randomly positions starbursts of random size and/or number of bursts about the screen. One could make a similar extension to the VariableStar program, creating a StarrySky, or even combine the two, as illustrated below. (Note how these efforts justify the restriction on the use of home in the Starburst activity, as that algorithm wouldn't support starbursts not centered at the center of the screen.)
  • Fireworks
  • Tannenbaum: write a script to draw a pine tree. Use variables so that you can easily modify the number of branches and the scale of the tree.
  • A Tesselation is an arrangement of shapes closely fitted together in a repeated pattern without gaps or overlapping. They range from the simple to complex. Code your own version of the arrows tesselation illustrated below, or alternatively program one of your own design or one found via a web search. Use variables to specify the number of rows and columns, as well as dimensions, so that you can easily change the size of the smallest repeated element.
  • Beyond the lesson

    Variable names

    The lesson does not list the rules for variable names, as such discussions can become needlessly tedious. The approach taken in this curriculum is for the teacher to provide further explanation when issues arise, because problems relating to variable naming generally arise in these initial lessons infrequently.

    The following list of rules is provided as a reference:

    Character restrictions
    A variable name cannot begin with a numeral (though it can contain numerals). It cannot contain symbols (*, $, #, ., etc.) with the exception of th eunderscore ( _ ).
    Case sensitive
    Variables are case sensitive, i.e., Name and name are different variables.
    Reserved words
    Any attempt to use a CoffeeScript reserved word, such as break or for, will result in a SyntaxError that prevents the program from running. A complete list of reserved words is available at this w3schools page.
    Predefined names
    This script provides a complete list of Pencil Code variables that belong to the global scope. These variables, which belong to the window object, can be referenced by name from anywhere in the script. JavaScript also has several top-level functions: eval, isNan, Number, String, parseInt, parseFloat, escape, and unescape. CoffeeScript and jQuery each add additional predefined variables.

    It is possible to assign a value to to a name that matches one of these predefined references, and thus overwrite it. For example, there is nothing to stop one from coding black = 9 or bk = "black". However, unless the desired intent is to replace the original value referenced by the built-in variable, this should be avoided. Using the name of an existing function or variable causes the user to lose the ability to reference the original function or value. Moreover, it can lead to runtime errors. For example, the following script will run but crash on the fourth line, reporting a TypeError because at that point fd references a number, not a function.

    dot blue, 6
    fd = 9
    rt 90
    fd 100

    Clearing Text and Graphics

    cs is one of three functions that can clear elements in the document window, the others being cg (clear graphics) and ct (clear text). These other functions become more relevant as we add additional features to our programs, such as additional sprites and text; they will be addressed in the notes to the Add More Turtles! lesson and in the Add Text! lesson.

    Primitive and reference data types

    A reasonably accurate description of variables is that they are simply "named containers," as illustrated in the following diagram for a variable x.

    However, there is an additional level of nuance to this description that depends on what type of value the variable "contains." The issue involves how Javascript stores that information in memory, and this in turn has implications for how references to a data value, via the variable name, impact that underlying value.

    All data values can be categorized as either primitive or non-primitive. Primitive values include all data types that can be represented with a fixed amount of computer memory. Primitives include numbers, strings, and boolean values, as well as the special data values null and undefined.

    Diagramatically, we can depict variables referencing primitive data values as being directly associated with that value:

    Non-primitive (a.k.a., reference) values include various manifestations of the Javascript object data type. These include objects such as turtles and sprites, but also arrays and even functions. The distinguishing characteristic of objects is that they are collections, i.e., they can contain any number of values. Given this flexibility, the contents of objects cannot be expected to fit in a fixed amount of memory, as is the case with primitive values. As a result, the value associated with the variable name is not the data value itself, but a reference to the object (essentially, a pointer the memory address where the object is stored).

    Diagramatically, it is common to depict the references of variables associated with objects with arrows pointing to the underlying objects. The following diagram illustrates the fact that, in contrast to primitive data values, two or more equivalent but distinct non-primitive values (here, two green Turtles, both located at the origin and facing north) can exist simultaneously.

    The difference between how primitive and non-primitive values are associated with variable names has implications for working with the underlying data. These are perhaps best illustrated using simple examples. Continuing with the example begun above, consider first what happens when the primitive variable y is assigned to x. As the following diagram illustrates, this does not cause the variables y and x to point to a shared value in memory. Rather, it results in the creation of a duplicate copy of the primitive value, 3:

    Given the duplicate copies, subsequent changes to one of the variables (here, to x) has no effect on the other:

    Manipulations of variables associated with non-primitive values result in a different pattern of change than with primitive values. The underlying cause of this is that, when working with non-primitive data, multiple variables can reference a shared object in memory. This is illustrated in the following diagram, in which the assignment of a to b results in the two variables being aliases for the same underlying object. When subsquent manipulations are made to the state of the object, it doesn't matter which variable is referenced to elicit those changes, because they refer to the same object. Thus, in this example, a.wear red would have had the same effect.

    The differences between primitive and non-primitive variables have important consequences, and can be a frequent source of coding bugs, such as when attempting to compare objects, copy objects or collections of objects, or pass objects to functions as arguments. These pitfalls will be discussed further in the relevant future lessons.

    Compound assignment operators

    The operators +=, -=, *=, and /= perform a calculation on a variable with subsequent assignment to that variable. For example, myVar += 5 is equivalent to myVar = myVar + 5. These operators all work with numeric values.

    Additionally, += works with strings. In that context, += serves as a concatenation operator (the string data types will be discussed in depth in the Add Text! lesson). While premature to introduce these operators now, they will be useful shortcuts in time.

    Comparison operators

    Whereas = is used for assignment, the Boolean operator == is used to test for equality. Students will learn about == and other Boolean operators in Comparison Operators! . It is at that point where somewhat difficult-to-identify bugs involving = mistakenly employed as a comparison operator will arise. Typically, however, the problem is not conceptual, but one of execution, i.e., the student will inadvertantly type = where he or she intended to have ==.

    Multiple assignment

    Coffeescript (like Javascript) allows for assigning multiple variables in a single statement, e.g.,

    x = y = z = 3

    This can be a convenient shortcut!

    What can go wrong

    Variable Names

    Rules for variable names were described above. The most common errors arise from inconsistency of capitalization, such as inadvertenly coding myVar in some instances, and myvar in others. Depending on use, this may or may not yield an error. In the latter case, debugging can be particularly challenging, especially for new coders.

    Syntax of math operators

    The syntax for using math operators is more restrictive in coding than in math class. This arises because the rules by which CoffeeScript parses code, though consistent, is not clearly evident at all times. For example, if x points to a numeric value, then x = x +5 will result in a syntax error, but x = x+ 5 and x = 5 +x will not. Typically, all that is needed to express our code in a way that CoffeeScript will interpret it as we want is a minor change, such as adding or removing a space or in the case of multiplication, making the * operator explicit.

    The following is a list of common mistakes, and their solutions.

    y = y +1
    CoffeeScript interprets the expression y +1 to be an attempt to call the function y with argument +1 (as if you had coded y = y(+1) ). It therefore crashes at runtime, reporting a TypeError, because y is a numeric value rather than a function. The fix is to add an additional space (yielding y = y + 1) or to remove one (y = y+1), so that the compiler recognizes + as the addition operator. This error also occurs with the minus operator.
    y = 5x
    What should have been entered is x = 5*x. Coding x = 5x leads to a SyntaxError, a problem that CoffeeScript identifies at compile time, prior to execution of the program. As a result, in this case, none of the source code will run, but CoffeeScript will highlight the offending line of code in the editor.
    y = x5
    What should have been entered is x = x*5. CoffeeScript identifies x5 as a valid variable name, and will result in a ReferenceError (crashing at that line of code during run-time) unless a variable with that name actually exists in the script.
    y = 5(x+1)
    The expression to the right of the assignment operator should be 5*(x+1). The parentheses around the second factor, x+1, cause Coffeescript to misinterpret the x+1 as an argument to a function named 5. Because 5 is not a valid variable name, this results in a SyntaxError that crashes the program at compile time.
    y = (x-1)(x+1)
    The expression to the right of the assignment operator should be (x-1)*(x+1). The parentheses around the second factor, x+1, cause Coffeescript to misinterpret the x+1 as an argument to a function named x-1, resulting in the programming reporting a TypeError when it reaches this line.

    Pedagogy

    Coding style and expert habits

    Effective use of variables is a key foundational step for coders. Getting started with variables early and getting practice often will help students develop a better coding style overall, which will serve them well as they write longer and more comlicated scripts. As noted in the lesson, use of variables in code can facilitate code maintenance. It also sets up good habits that will facilitate the transition to coding with functions with arguments. The importance of good habits cannot be overstated.

    Previous lessons and teachers notes emphasized letting the computer do the math. For example, when coding a pentagon, it's preferable to write 360/5 to hard-coding 72. With variables, we take it a step further, declaring sides = 5 and later instructing the computer to compute turnAngle = 360/sides. Combined with thoughful choice of variable names, showing math greatly benefits readability and code maintenance. Code written this way is said to be self-documenting. It also avoids burying magic numbers in the code, i.e., unique values with unexplained meaning or multiple occurrences which could (preferably) be replaced with named constants.

    In teaching students these habits, it is useful to show an example that allows them to see the difference for themselves. Lesson uses the example of code used to draw a pentagon, which could alternative look like this:

    for [1..5]
      fd 100
      rt 72

    or like this:

    #draw a pentagon
    points = 5
    sideLength = 100
    for [1..points]
      fd sideLength
      rt 360/points

    The latter shows more of the logic. It allows the coder to quickly and confidently change the program to any number of points, and also gives greater insight into the logic of the computations. This latter advantage becomes increasingly important the more complicated the computation or lengthy the script.

    True, there is a tradeoff: the better-documented code takes more effort to write. However, the benefits of good style habits will outweigh the costs in the long run, as students begin to write longer and more complicated scripts that involve many different parts.

    Technicalities

    Increment and decrement operators

    Two additional operators useful when adding or subtracting 1 from a numeric value are the increment operator and the decrement operator, denoted ++ and --. For novice coders, these expressions are useful when used as stand-alone statements. For example, myVar++ is equivalent to myVar = myVar + 1.

    ++ and -- can also be used in more complicated ways. They can be embedded in other expressions. Additionally, they can also be placed before a variable name, which impacts the execution of the resulting expression: putting ++ before the variable name increments the value before its value is evaluated in an expression, while putting ++ after the variable increments it after it is evaluated. An illustration of how placement of the increment operator affects computations is provided here. The difference is nuanced and is a source of significant confusion even for higher-level coders.

    Fundamental data types

    In Coffeescript, as in Javascript, variables point to one of seven fundamental data types. In this book, we will explicitly work with Boolean, Null, Number, String, and Object types. The Boolean, String, and Object types will each be addressed directly in subequent lessons. The concept of data types, more generally, will be explicitly addressed beginning with the Date Objects! lesson.

    Javascript is said to use weak typing because the data type for a variable can change. (Contrast this with the behavior of a language like Java, in which a variable must be declared with a specific type, and once declared, cannot be changed. This is known as strong typing.) The Javascript typeof function can be used to determine what type of data a variable currently references, as illustrated by the this script.

    undefined

    The process of creating a variable actually involves two steps: declaring the variable (giving it a name), and initializing it (assigning it a value). Javascript makes these steps explicit, through use of the var keyword, as illustrated in the following example.

    var x = 5; // x has type number and a value of 5
    var y;     // y is has type undefined and value undefined 

    The takeaway from the preceding illustration is that in Javascript, if you don't initialize that variable in the same statement as the declaration, the variable will be (for the time being, anyway) undefined. undefined is a special data type with the specific role of identifying variables that have not been assigned a value, and therefore is not one of the other data types, such as number, string, or object.

    CoffeeScript does away with the JavaScript var keyword. However, it is possible to create variables that are not assigned a value, but one must do it explicitly:

    y = undefined     

    Students are unlikely to generate undefined variables themselves, but they will undoubtably encounter error messages about undefined variables at some point.