Skip to main content

Day 16 - Testing and variables that change

Skills: 3

Pre-reading: DRAFT:9.1.8.5.4

Intro (15 mins)

  • All our uses of mutable variables have intentionally followed the same pattern:
    fun func(lst :: List) block:
    var result = ... # what to return if the input list is empty
    for each(item from lst):
    # combine item with the result so far
    result := ... item ... result
    end
    result
    end
  • In particular, we only use var inside of functions. Why?
  • Consider we wanted to implement a function every-third-element that took a list, and returned the first, fourth, seventh, etc, elements.
  • If we wrote it as:
    var count = 0
    fun every-third-element(lst :: List) -> List block:
    var output = [list: ]
    for each(elt from lst) block:
    when num-modulo(count, 3) == 0:
    output := output + [list: elt]
    end
    count := count + 1
    end
    output
    where:
    every-third-element([list: ]) is [list: ]
    every-third-element([list: 1, 3, 5]) is [list: 1]
    every-third-element([list: 1,3,5,7,11]) is [list: 1, 7]
    end
  • It seems to work. But then we actually use it, adding every-third-element([list: 1,3]) somewhere in our code, and suddenly two of our tests are now failing. Why is this happening?
  • Since count is defined outside of every-third-element, it is put into the top-level program directory. This means that there is only ever one count, and separate calls to every-third-element share the same count.
  • This means two things, both of which are very bad:
    1. The function no longer returns the same output depending on the same input. Instead, the output depends on the input and the current state of count.
    2. This means, more confusingly, that to understand what a given call of every-third-element does, we need to know all the calls that have happened before, as the program ran, which may not be obvious from reading the program (since with looping, with one function calling others, etc, the order and how many times a function is called can be tricky to figure out).

Class Exercises (40 mins)

TODO -- do we want them to trace behavior with confusing variable mutation examples? Or convert them to be pure? Or both? This is a difficult objective given the lesson is essentially "don't do this".

Wrap-up (5 mins)