PencilCoder

Teacher's Guide: Arrays!

Overview

This lesson formally introduces arrays, a specialized type of JavaScript object. The lesson shows students that they can create arrays of other values besides numbers, including colors (which, technically, are references to strings) and sprites. The lesson also illustrates the usefulness of traversing over this wider variety of arrays and using arrays as arguments to the random function.

This is the first of several lessons which will explore a range of array features. In this lesson, the focus is on creating arrays using array literal syntax (i.e., brackets) and traversing arrays in "for x in" loops. Other aspects of arrays will be addressed in subsequent lessons: Array Destructuring!, Push and Pop!, and Subscripting!.

More about the lesson

Students have been using arrays, though perhaps unknowingly, since the For Loops! lesson. The syntax [1..4] (or, equivalently, [1...5]) is a CoffeeScript shortcut for the array [1,2,3,4]. Although this syntax does not provide an apprieciable advantage for coding such short arrays, students can surely appreciate its value for longer ones (e.g., [1..1000].

The lesson notes that arrays can hold any type of data value. Because Arrays are a special type of object, this means that arrays can also contain other arrays. For example, the following array contains three arrays:

identityMatrix = [[1,0,0],[0,1,0],[0,0,1]]

Terms describing such structures include nested arrays, two-dimensional (or 2-D) arrays, and matrices.

Because functions are also a special type of object (a feature explored in the Callbacks! lesson), they can be referenced in arrays. Finally, arrays can also hold mixes of values, e.g, ["abc", 1, turtle, fd]. This feature can be useful when returning information from a function. As students will learn in the Return! lesson, functions can only return a single value. But since that value can be an array, the amount of information they can return is effectively limitless.

CoffeeScript array-literal syntax

Coffeescript is very flexible with array syntax, as the following three equivalent coding snippets illustrate:

Notes to activities

The Starburst and Rainbow activities are intended to be straightforward modifications of the earlier programs by the same names. Encourage students to start from scratch, rather than revisiting their previous programs and copy/pasting, so that they can work through the logic again. In the case of ROYGBIV, the new program should be much shorter than the previous one (from way back in Curved Line Art!).

The lesson's illustration for NeonLights assigns each turtle a slightly different speed to get the desired effect. Another approach involves capitalizing on features of the animation queue in a different manner, using sprite-specific calls to pause, as illustrated here. Yet another alternative could be to make clever use of the sync function.

TurtleVersusFrog involves an application of simple probability. Students may benefit from an explicit discussion in class.

The Starbursts activity provides students a variety of opportunities to work with arrays. The goal is for students to use nested loops, with the outer loop deterimining characteristics of each starburst (color, location) and the inner loop creating the burst. Point out to students that the use of variables to create the starbursts, rather than relying on home, is what enables it to be positioned anywhere on the screen (and therefore justifies the restriction placed on them when coding that activity earlier).

Students can randomly position the sprites using random with array arguments. Note the example solution's use of slide, which is a convenient one-liner for randomly positioning the sprite on the screen:

Additional activities

  • Copy your code from Variables/GrassyField to a new GrassyField program in the Arrays folder. Modify your code, so that it chooses for each blade of grass a color from an array of green Pencil Code colors. To make some shades more likely than others, refer back to the approach used in the lesson's TurtleVersusFrog activity.
  • Grassy Field Image
  • Grassy Field Image Choreography: Instruct a group of five or more sprites perform a synchronized dance. This is similar to a previous activity, TeamTurtles, except this time your should use arrays to create a vastly shorter script.
  • GrooveMixer: code a program that repeately selects randomly from an array of short snippets of music, or riffs, to compose original works each time. As an extra challenge, include different but compatible riffs for both the right and left hands.
  • SimonV1: Lay the groundwork for coding your own fully-functional version of the game Simon. For this activity, code four custom sprites, one for each colored light. Define an array that references each of these sprites, which you should use with the random function to randomly make individual lights turn off.

    Blank space Blank space

    In later lessons, we will revisit this program, adding features such as memory (creating, storing, and traversing arrays of randomly generated light sequences) as well as the ability to actually play the game interactively (using mouse clicks).

  • An array keeps track of multiple pieces of information in linear order, a one-dimensional list. However, sometimes it makes sense to think of data in terms of two (or more) dimensions. A two-dimensional (2-D) array is really nothing more than an array of arrays. In math we refer to this type of structure as a matrix.

    Create a DieMaker program that stores the dot pattern for each face of a regular six-sided die using two-dimensional arrays. To do this, think of the face of the die as consisting of three rows and three columns. For each of the six faces, use an array that contains three arrays (one for each row), each of which contains three elements (one for each column). For example, you might store the information to create the face for three as three = [[1,0,0],[0,1,0],[0,0,1]], where a 1 indicates the presence of a dot, and 0 means no dot. (You could just as easiliy use true or false, but that is a lot more to type!) Write a loop to generate images of each face of the die.

  • Use 2-D arrays and nested loops to create your own PixelArt. The image map on the left was used to create the image shown on the right.
  • Blank space

Beyond the lesson

Anonymous arrays, anonymous elements

Oftentimes coders will create and use an array without without naming it, resulting in an anonymous array. For example:

In the preding example, the anonymous array is defined with references to variables. However, one can at times even skip that naming process, using anonymous references within anonymous arrays:

Use of such anonymous arrays and/or anonymous references is useful when the items in the array only need to be referenced in that part of your code. In the example above, the coder loses all references to the red and blue turtles once the for loop terminates. But that is OK if we don't need to reference it again later.

This idea of creating objects anonymously for single use will appear repeatedly in other contexts as students progress as coders. An important example is the use of anonymous functions.

jQuery.turtles.colors

The built-in array jQuery.turtle.colors (equivalently, $.turtle.colors) contains references to all predefined HTML color names as well as transparent. A simple use of this array is as an argument to the random function, thereby choosing from the 149 predefined colors, rather than from one of 360 HSL codes selected when using random(color) (as described in the Notes to the Colors! lesson). Activities in subsequent lessons will make use of this array.

splats (...)

Students have seen that ... can be used as a nuanced alternative to .. when creating arrays of numeric values in CoffeeScript. For example, [0...3] creates the array [0,1,2]. However, this three-dot symbol, referred to as a splat, serves another useful array-related purpose, though in a more limited context.

In the context of passing an array to functions that expect multiple comma-delimited arguments, rather than an array of elements, the splat converts the array to the appropriate form. For example, the built-in JavaScript function Math.max does not accept arrays. Thus, the following code would cause an error:

values = [3,5,2]
Math.max values

However, Coffeescript evaluates the expression Math.max values... as if the coder had entered Math.max 3,5,2, with evaluation of either expression returning 5.

Like max, the sync function also accepts multiple arguments, but does not accepts arrays. Thus, if racers references an array of Sprites, sync racers... will function correctly.

Pedagogy

Terminology

The Technicalities section points out an intentional minor abuse of terminology in this lesson involving what is actually stored in an array. However, in this curriculum such deviations from accurate terminology is the exception and not the rule. Continue to use computationally precise language. For example, the lesson weaves in the terms iteration, references, arguments, traversing, and statements. It is not essential that students master this vocabulary immediately, but the instructor's consistent use of such terms will help students develop over time and contribute to a more rigorous understanding of the coding language and concepts.

Technicalities

Array constructors

Arrays are a special class of JavaScript object. The lesson instructs students to instantiate arrays using array literal syntax. For example, values = [ ] creates an empty array and values = [5,6,7] creates an array with three numeric elements. Array literal syntax is by far the easiest and least problematic approach to creating arrays.

Similar to other classes, such as Turtle and Sprite, arrays can also be instantiated using the Array constructor. For example, values = new Array(5,6,7) is equivalent to values = [5,6,7]. However, use of the Array constructor can lead to confusion and is generally discouraged. The primary complication is that when it is passed a single numeric argument, the Array constructor creates an array of a given length, setting each element of the array to undefined, rather than creating a length containing that value. For example, values = new Array(3) is equivalent to:

values = [undefined, undefined, undefined]

References and values

The Notes to the Variables lesson devotes a section to the difference between how variables associated with primitive values (e.g., numbers, strings, and booleans) and non-primitive values (e.g., collections—namely objects) are stored in memory. Variables associated with primitive values are linked directly to the actual data value in computer memory. Variables associated with objects, in contrast, store a reference to the data—i.e., a pointer to the location in computer memory where the underlying data are stored.

Because arrays are objects, a variable assigned an array doesn't actually contain the array itself, but rather a reference to that array. One implication of this design feature is that superficial attempts to copy that array will create aliases rather than new arrays. Any manipulations to the elements of the array via the alias will impact the elements in the original array just as if the original variable name were used. For example, consider the following coding snippet:

turtles = [ new Turtle(teal), new Turtle(coral) ]
sameArrayDifferentName = turtles
for t in sameArrayDifferentName
  t.wear random(color)      

This code does not create an array of new sprites, but rather another variable that contains a copy of the reference to the original array; the sprites referenced by turtles therefore end up with new colors, because they are the same sprites referenced by sameArrayDifferentName.

To copy an array, one needs to instantiate a new array and copy each of the elements over. This process (which is the approach used by the built-in Array method copy) is referred to as a shallow copy. However, this is not an effective approach in all cases. A shallow copy will fail to create a true copy of the original array if the elements of the array are themselves objects. Rather, it will copy references to the same objects that are referenced in the original array. When the goal is a new array with copies of all objects contained in the original array, the copy process needs to be repeated recursively until primitive elements are reached, using an approach known as a deep copy.

Students are unlikely to attempt to worry too much about copying arrays at this point. However, they may run into trouble if they attempt to update the values in an array using reassignment, in particular in the body of a for x in loop. For example, consider the following code:

numbers = [1,3,5] 
for n in numbers
  n = 2*n

The values in the numbers array remain unchanged after the loop. Within the loop, the variable n is updated; but the very process of assigning a new value to n breaks the link to the underlying array from which n was drawn. This same result applies even if the elements of the array are objects.

Changing a value in an array requires other tools, such as the push and pop methods of the Array class (see the Push and Pop! lesson) and bracket notation (Bracket Notation!).