PencilCoder

Teacher's Guide: Push/Pop

Overview

The primary goal of this lesson is to introduce the Array object's push method, which provides students with a means to generate arrays of values using iteration. This feature of arrays will be used repeatedly in subsequent lessons.

More about the lesson

The Arrays! lesson instructs students to create arrays by enclosing a comma-separated list of values or variables within brackets. This generally-preferred method to create arrays approach approach formally referred to as array literal notation. Students also learned to traverse arrays, first using for loops, and later while loops.

The ability to iteratively build up arrays of values or objects using push is a simple yet powerful extension to students' coding skillset. This is illustrated in the lesson's coding snippet, which uses push to create an array of 100 turtles. Previously, students would have to write code such as the following to accomplish the same result (though this array contains far fewer than 100 sprites!):

As noted in the lesson, push is also a useful tool for writing code to create and populate arrays of lengths unknown to the programmer. The example provided in the lesson, user input, is admittedly not directly relevant to students just yet, as this curriculum does not explore such features for several more lessons. A more concrete example to provide students now is creating an array of a random number of sprites, which is illustrated in the following example—which also illustrates that with a few additional lines of code, we can guarantee that each sprite has a unique color:

turtles = []
colors = []
for [1..5+random(20)]
  c = random($.turtle.colors)
  while c in $.turtle.colors or c==transparent
    c = random(color)
  colors.push c
  turtles.push(new Turtle(c))      

A final observation which should be shared with students is that the elements that are used to populate arrays using push are often added anonymously, i.e., without ever giving those values or objects a specific variable name. This is true of the preceding example. Students would need to iterate over the resulting array to access any particular element; in later lessons, students will also learn about subscripting as a means to access individual elements of an array.

Notes to activities

The push and pop functions and length property are easy to understand and use. The activities in this lesson provide students with opportunities to apply these new tools, but the real challenges to the activities involve logic and the application of functions and structures learned in previous lessons. Most students will realize that all activities in this lesson call for using iteration, though some students might benefit from a nudge in that direction.

The RainbowMaker activity is included as a relatively straightforward warmup. Admittedly, it is a fairly silly example, as students could easily accomplish the goal without creating the array of turtles using push. For example, a more concise solution is to instantiate and move turtles while traversing the array of colors—there is no need for a second loop. It may be worthwhile to share this point with your students, if they don't realize it on their own. Subsequently pointing out that the program can be written more simply, without the use of push, could itself be a good lesson—new tools don't necessarily ensure the most elegant or efficient code!

The UniqueRandNum activity requires students to search through an existing array. Students can try to devise their own search algorithms, using iteration and conditional logic, though the use of the in keyword, as described in the lesson, makes the task much simpler. Given a value, x, and an array of values, numbers, the expression x in numbers yields the boolean value true if there is a match. Note, however, that the use of in in this context comes with an important caveat. It typically only works when the value sought for in the array is a simple value, such as a number or string, rather than an object, such as an array. Comparisons will typically not work with objects, because the comparison is made to the object itself, rather than based on the contents of the object. This point is explored further in the notes to the Additional Activity Gridders, below.

Additional activities

  • SquiggleBurst: Create a new version of StarBurst that has randomly-twisting bursts that are outlined in black. Do this by first drawing the burst in black, keeping track of your movements using push; then retrace your steps back to the center of the burst using a thinner colored pen, with movements determined by calls to pop.

  • InstantReplay: Create a variant of the now-classic TurtleRace activity (first introduced in Add More Turtles!) that shows a quick race, followed by a slow-motion replay of the final leg of the race.

    Hints: use of touches complicates matters, owing to the need to deal with the associated animation-queue considerations. A better approach is to base conditional logic on the cumulative distance traveled by each sprite, comparing it to the total needed to win. Solutions might include "rewinding" the race from the end (using pop and then playing that again; though the model solution uses a slightly different approach.

  • SwissCheese: Create a slice of swiss cheese, by drawing a yellowish (lemonchiffon?) square with lots of white dots in it. However, to make it more realistic, outline each dot with a slightly darker color (such as palegoldenrod). In attempting to add these outlines, you will likely encounter a disappointing result. Come up with a better solution, which will incorporate the use of push.
  • CreateCards: The following statement creates an array of strings with the UTF-8 representation of the symbols for card suits, ♣, ♦, ♥, and ♠.

    suits = ['\u2663', '\u2666', '\u2665', '\u2660']

    Create another array to represent card face values ('2' through 'A', for Ace). Then combine these two arrays using nested for loops to create "cards", such as the string 9♠ (or the array [9,♠]) which you should save to a single array using push.

    Randomly select a single card from this array. Use label to show the selected card on the screen, nicely formatted.

    (As an extra challenge, select two or more cards, without replace-ment, meaning that you should have no repeats.)

  • Gridders: Create an array of several turtles, each with a different color. Have these turtles move around a confined space, such as a 250x250 box. They should always move N, S, E, or W in steps length 25. When a turtle encounters a space that no other has visited previously, it should make a 25x25 box matching its color. However, do not use touches to determine if a space has already been claimed. Rather, track the coordinates of each location using an array of two values, e.g., loc = [75,-25], and store all such arrays of coordinates in another array of claimed spaces, using push. Keep the turtles moving until the entire 250x250 box has been filled in.

    Note: The approach of representing coordinates as arrays has an important implication for use of the in keyword to test for whether a specific coordinate already exists in the collection of claimed coordinates. As noted above in the discussion of the lesson's UniqueRandNums activity, boolean tests using in typically only succeed when the values being searched are so-called simple, or primitive, data types, such as numbers or strings—in fact, anything other than an object (which includes arrays, as they are a special, built-in form of object). Rather than use in, the solution requires evaluating both values in the coordinate. This can be accomplished with the help of array desctructuring to break up the location into two variables, and then conditional logic to individually compare the x and y values of the new coordinate with the x and y values of the locations stored in the array of claimed spaces.

  • GetDigits: Write a script that converts a large integer into an array of digits. There are many ways to accomplish this; for example, a pro JavaScript coder might whip up a clever one-liner involving built-in Number and String functions, e.g., x.toString().split(""). However, you should tackle this exercise using successive calls to the mod operator, %, to isolate the right-most digit, and add this value to an array. Note, calls to push will cause your values to be in reverse order; but thankfully, this is not too difficult to fix. See if you can figure out how to use pop and push (and a second array) to get these values into the original order. However, there is a simpler alternative, which is to use the function unshift rather than push. The functions unshift and shift work analagously to push and pop, except they add or remmove elements to the front end of the array.

  • StringArt and ParabolicArcs: Khan Academy has a fantastic introduction to modeling curved lines, based on string art, as part of its "Pixar in a Box" series. Follow the lessons to come up with your own script to code a parabolic arc!

Beyond the lesson

In addition to appending an element to the end of an array, calls to push also return a numeric value, equal to the length of the array after the new element has been added. This feature won't be ulitized in this curriculum, though it can be harnessed in powerful ways, as illustrated in this script.

pop always returns a value. This will be the element removed from the end of the array, unless the array is empty, in which case pop will return undefined. This is useful, because it means that calls to pop will not directly lead to runtime errors in CoffeeScript.

This lesson does not make broad use of pop. Though students may not have much use for this method of the array class at this point, it is of central importance to the operation of the call stack, a central feature to how computer programs themselves operate. Stacks are also the structure that underly the widely implemented "undo" function (a.k.a., Control-Z / Command-Z). pop will be of greater potential use to students once they learn features to make their programs more interactive, such as responding to events, a topic not taken up until students have gained some experience with custom functions (the next lesson).

shift and unshift

push and pop work from the tail end of an array. We can similarly remove or add elements to the front of an array using the unshift and shift methods. This is illustrated in this simple script.

Subscripting

A seemingly natural extention of this lesson is to introduce the subscripting feature of arrays, which provides access to specific elements of arrays based on their indexes. However, subscripting can lead to a host of technical and logical challenges, which can outweight the benefits from these additional tools at this stage of development, and thus will be taken up in a later lesson.

Setting the length property

CoffeeScript allows users to set as well as access the array length property. Assigning a value to the length property will add or remove elements from the array. Assigning a value that is shorter than the number of stored items truncates the array; assigning 0 empties it entirely. Setting length longer than the number of existing elements sets all new elements to undefined. An example of this feature is illustrated in this script.

What can go wrong

Use of push and pop are unlikely to lead to many errors directly. Given the weakly typed nature of JavaScript (i.e., a variable can reference any data type), students can push values of any type (i.e., number, string, object) to any array. pop will likely not lead to errors directly, but it can indirectly, if students attempt to remove elements from an empty array. In this case, pop will return undefined. Depending how that return value is subsequently referenced, it could lead to confusing results or (if the expected value is an sprite and methods are called on it) a runtime error. The best advice to avoid this result is to verify that the length of the array is positive before calling pop.

pop ignores any arguments passed to it. A common misunderstaning is an attempt to pass a value to pop, either intending it to represent the index of an element in the array, or representing the value that the user desires to remove. Either way, pop will ignore the argument and simply return the last element in the array, or undefined if the array is empty.

Technicalities

Language-specific features of Arrays

Arrays are a data structure commonly found in programming languages. However, the functionality and behavior of arrays in each language can vary greatly. For example, the use of push and pop in this lesson illustrates that in JavaScript, arrays are mutable. This means you can not only change the contents, but also the length of the array. This is not the case in all languages. In Java, for example, the length of an array is fixed when it is initialized. There are various additional such differences between these languages. The upshot is that when turning to other languages, one needs to be on the lookout for language-specific features.

Loop Expressions

In CoffeeScript, nearly all expressions evaluate to a value. This applies not only to expressions such as 5*5, which evaluates to 25, but also to expressions such as assignment. For example, w = 5 is itself an expression, with a value of 5. This CoffeeScript language feature is what allows for multiple assignment, such as h = w = 5.

Loops, too, are expressions, and thus each loop also evaluates to a value. In the case of loops, the resulting value is an array. A loop with n iterations will evaluate to an array of length n, with the elements of the array set to the value of the expression of the last line in each iteration. The upshot of this is that users can effectively create arrays without explicitly calling push. For example, the following two snippets yield analogous results:

turtles = []
for [1..100]
  turtles.push(new Turtle(random(color)))

is effectively identical to

turtles = for [1..100]
  new Turtle(random(color))

See this example script for additional examples, including a peak at the CoffeeScript when filter feature and postfix comprehensions—two topics beyond the scope of this curriculum!