During a recent reading on CS education, I came across this paper – “Effect of active learning using program visualization in technology-constrained college classrooms” – by scholars at Indian Institute of Technology (IIT), Mumbai. The paper looks at the impact of program visualization in instructor mediated CS classrooms. What they found was a significant increase in student engagement and learning when Responding was implemented instead of Viewing. As in, visualization of code presented by the teacher but with active student participation in predicting the outputs had better cognitive achievements in students.
One of the challenges in computer programming is how abstract the process can quickly become. Even if the final outcome is provided, if the process of how the program is getting there is not clear, then concepts cannot be retained. For instance, the output of a piece of code may be exactly what you expect it to be, but without knowing precisely what is happening at each line, with each variable, with every function call, the storage loads in memory etc, the learning process can start creating significant gaps over time. I have seen this several times in my classes with students being able to produce the right results without completely getting a stronghold on why some the constructs are behaving the way they are in the code. This becomes more evident in their answers while tracing algorithms in an exam setting. Despite the code being given to them beforehand, inability to visualize effectively creates challenges that go beyond just getting the “right answer”. Program flowcharts help, to a certain extent. But as the complexity of the code increases being able to reproduce these charts for every single element becomes a challenge. So these charts are best used for generalized ideas of what a method or construct is doing in the code.
An example is this simple program that uses an array to convert a value from Binary to Decimal. A single array holds the bits represented for the number and the program goes through them one by one multiplying their place value with base 2 and creating subtotals for the final decimal equivalent.
def bin_dec(binArr): #function starts here result = 0 #variable to hold final answer for i in range(len(binArr)): #loop through each digit in the array if binArr[i] == 1: #only 1 position elements have a power result = result + pow(2,len(binArr)-1-i) #total calculated by squaring arrpos(length-1-i) #We do this because digit powers start from right but array is being navigated from the left. #So for 1100, the first 1 is  in array but in position 3 as a number. #Hence, len(binArr)-1-i for that position gives u : len(binArr) = 4 -1-0 (since i is 0 at this point) #4-1-0 = 4 - 1 = 3. 2 power 3 is what we want for first 1. #continue loop for all elements in array return result #return output print(bin_dec([1,0,0,1,1,1,1])) #79
When I pass this code into PythonTutor the following screen shows up.
Some important points to note:
- The layout makes it easy to track each line executed and the variable changes that take place.
- The slider lets you go between different stages of the code. An important element to understanding why your code is doing what it is doing.
- The allocation of memory for this array and position indicators are useful to know which index element is being processed at any given time.
- The Customize Visualization option at the bottom allows you to further customize the arrows, lines and curves for your needs.
Now, let us try this with a slightly more complex algorithm. In this one we write a program that accepts plain text and creates a cipher for it based on the key sent along with it.
def cipher(text,key): #function starts here arr = "abcdefghijklmnopqrstuwxyz" #lookup variable for all letters. text = text.lower() #convert original text to lower ctext = "" #variable to hold final output for c in text: #loop through every character in string #if c is part of alphabet, look up index of c in arr, add key value and mod the whole value by 26 #(for high value keys) and look up its equivalent in arr if c.isalpha() : ctext += arr[(arr.index(c)+key)%26] else: ctext += c #if c is not in the alphabet, then add it in as is. Example digits, special characters. return ctext #return final output back #testing function with same message but diff. cipher keys. print(cipher("Hello World 123",3))
When this is fed to PythonTutor the following visual appears.
You notice clean containers for each of the variables I am using along with the original text that was passed to the function. The key remains 3 during the entire process since that determines how the cipher works. With each step, the code is constantly updating the ctext and c variables as it tracks and converts every letter from “Hello World 123” to “khoor zruog 123”. This is critical since it lets you know which variables will never change the value the whole time and which ones will. And more importantly, why?
I have written about using the IDE as a coding mind map in the past. Combining good documentation skills within the code and a tool such as this to visualize the code can create an excellent case for strong cognitive enhancement in students. Not only can can they see the code unfold but can also predict what is going to happen next. The ability to accurately predict code is perhaps the real skill in the world of problem solving that is most relevant at the end of the day. So, give the platform a try and have fun!