I saw this tweet asking “how to teach coding without a computer”. In my typical fashion I started tweeting out a reply, but then I caught myself (I’m learning!) that the tweet barrage that would ensue is not a good way to answer the question. And so, we’re here.
The question as posed is a good one. There are many aspects to coding / programming that do not require the computer. However, there are a few key things worth mentioning and defining.
Programming is broad. And thus, in this article when I discuss programming I want to narrow it down to two main items: syntax and algorithmic thinking. By syntax I mean, “the manner in which a program is written”. As anyone who has had a basic introduction to programming can tell you, many programming languages are finicky about how things are typed. Thus, by and large, the syntax is non-negotiable nor can it sensibly be taught sans a computer (and a compiler, etc.). Algorithmic thinking, however, can be introduced and a sense of procedure can be taught without a computer. With that said, computer programming necessarily requires a computer, thus “teaching programming without a computer” is limited in a number of ways.
When I’ve taught a programming course or provided individual or corporate training one of the biggest stumbling blocks for students is fighting with the syntax. However, students often cannot differentiate between what is wrong algorithmically versus what is wrong syntactically. And since more effort is initially expended on “just getting the program to run”, algorithmic thinking skills play second fiddle.
What I have done in introductory programming courses is to first ignore all sense of syntax and get students to write out pseudocode. “Pseudo”, in effect, means “fake”, “not the real thing”, etc. I explain to students that
pseudocode is to a programmer what a light pencil sketch is to an artist.
All we’re doing is laying out a framework. Once we have settled on a framework, then we can build in details. An added side benefit is that since the student isn’t fighting with syntax, he/she can focus more on process and this helps to build algorithmic thinking.
In a strict sense, there are formalities to pseudocode, but with first time programming students I don’t get bogged down in these details.
If you are relatively new to teaching programming, you will find that even with writing pseudocode students can be sloppy and incomplete. This, of course, is natural. Students often will think a little too broadly for it to be meaningful. For example, if asked to write pseudocode for determining which is the largest number in a list of three numbers \(a, b, c\), some students may simply say something tautological like “look at the three numbers and pick the largest”. This is a good start, but the instructor wants to lead the students slightly away from fuzzy human thinking to something a bit more functional and, well, programmatic. As another example, when asked to write pseudocode that would swap the values of two variables \(a\) and \(b\) some students will say “make \(a\) equal to \(b\) and \(b\) equal to \(a\)”. And again, conceptually this is a correct idea for swapping, but if we thinking programmatically (not syntactically), this method of swapping fails since once we’ve “made \(a\) equal to \(b\)” we no longer know the original value of \(a\). We remember what the original value of \(a\) was, but programmatically the student needs to recognize that a temporary variable of some sort is needed and the instructor needs to coax that out. The idea of a temporary variable is lost because we, to some extent, take our memory for granted.
Thus, herein lies a difficulty for programming instructors. Students who are new to programming will not realize that their brain is doing an immense amount of fast processing even for a seemingly simple task like finding the largest number from a set of numbers. When the sets are small, our brain can take in all the information pretty much all at once and process it so quickly that any notion of programmatic / algorithmic thinking is hidden.
What is also hidden with “small size” problems is all the conditional processing that we do, almost automatically and seamlessly. A (large) part of computer programming is thinking in an “if, else if, else” manner. I’ve found that students generally have a hard time articulating how they know, for example, which number in a set of three given numbers is largest. They “just know” or the process that they give is tangled and not scalable (and not for reasons of computational complexity, but for reasons of logic).
Thus, when teaching a programming course, I encourage instructors to think big. Don’t ask “Write pseudocode for determining which of \(a, b, c\) is the largest”, but rather, ask, “Write pseudocode for determining which of “1773, 1394, 5359, 6600, 6210, 3312, 5918, 2521, 6176, 5450, 2062, 6117, 528, 8129, 2254, 5049, 9446, 6750, 8242, 2544, 1266, 2780, 7042, 4652, 7795, 4269, 7108, 6180, 4860, 8642, 1797, 6410, 2353, 4062, 9294, 2367, 5471, 1517, 7993, 5547, 4673, 670, 2697, 2091, 7192, 2966, 7810, 2084, 4457, 3195, 449, 6426, 9474, 9676, 4550, 7559, 5021, 3839, 9087, 8959, 680, 7412, 5547, 5543, 647, 7872, 2112, 5178, 8627, 5510, 9940, 6979, 1626, 2783, 6690, 4720, 1083, 4444, 6512, 8111, 4610, 5643, 1325, 7199, 7449, 6236, 9106, 3438, 2342, 1685, 9096, 7827, 4157, 1605, 46” is largest (and in the “real world” we are talking about millions of numbers).
In the rest of this article I will give a number of exercises, some written, some hands-on, for “teaching programming without a computer”.
As this is a math blog, there will be some math activities, because you know, that’s why people keep reading. 🙂
The overarching theme of these exercises is “how-to” and in my experience, that’s been a great way to engage students in practically any subject. Also, in a similar vein to my integrating finance into every subject post, the interested instructor will find that many aspects of programming too can be woven into every subject.
The remainder of this article is organized by “programming element” — that is, exercises that promote the use of “if-else” clauses, loops (for, do-while, while), functions, objects, etc. A note of caution: when dissecting a subject into “key components” it’s important not to lose the fact that those components interact with each other. Math education, for instance, suffers from this when instructors focus on individual concepts, ideas, and techniques and never synthesize them together into something useful. Learning to program is similarly not just about the programming elements.
There are many more activities and exercises for practically all subjects. Here, I give a non-exhaustive sprinkling of examples. If you, through your school, are interested in training or more activities like these, just get in touch with me and we can look to work out an arrangement. The easiest way is to message me on Twitter @shahlock or get in touch via Think. Plan. Do. LLC.
If-Else
Our lives are governed by rules. Rules come in the form of “if-then”. If the traffic light is red, then you must stop. If your class average is greater than or equal to 93, then you get an A. If you take out a mortgage, then you have to make periodic payments as spelled out in the mortgage contract, otherwise the bank will consider you to be delinquent and a different set of rules may begin to apply. If you eat an appleseed, then an apple tree will grow out of your stomach.
In programming, the “if-else” clause is a staple for decision-making. The basic idea is to see if a certain set of conditions are met and if they are, then to carry out the relevant commands. If the conditions are not met, then a different set of commands should be executed.
Let’s take a look at a few subjects where we can apply this idea of “if-else”.
Mathematics
The framework of mathematics, especially in the world of computation, practically begs for computer programs. Mathematical theorems all have conditions and assumptions that have to be met in order for the result of the theorem to be guaranteed. For example, in order for us to divide two numbers, we must have that the denominator is not equal to zero. This is a rule. There are reasons why, but in the world of how-to, it’s a rule. Thus, $$\frac{5}{0}$$ is not allowed.
From a programming standpoint, when applying a theorem, we first have to ensure that the conditions of the theorem are met. This conditional checking can be done in a variety of ways depending on the programming language. One broad way of checking conditions is to apply the “if-else” clause. In pseudocode this works as
if condition is met then: execute program else: do not execute program
Here’s a simple exercise to get students used to the idea of “if-else”. We can think of the division rule as follows when working with real numbers: “If the denominator is zero, then do not attempt to divide. Otherwise, divide.”
Now, if we were to think like a computer program, what would happen in the following cases? Do we divide or do we not divide?
- The numerator is 3, denominator is 5.
- The numerator is 5, denominator is 3.
- The numerator is 0, denominator is 6.
- The numerator is 0, denominator is \(\frac{-2}{3}\). (How do we check the validity of the fraction?)
- The numerator is 4, denominator is 0.
- The numerator is -4, denominator is 0.
- The numerator is 0, denominator is 0.
Here’s another example: there is a notion of a “piecewise defined function”. One example is the classical “absolute value” function defined as
$$
|x| = \left\{\begin{aligned}
&-x & if & x < 0\\
&x & if & x \geq 0
\end{aligned}
\right.$$
There are several ways to read the definition above. A programmer may translate the definition as “If \(x\) is less than zero, then absolute value of \(x\) returns the value \(-x\). If \(x\) is greater than or equal to zero, then absolute value of \(x\) returns the value \(x\). Else, we have undefined behavior.”
Some may ask or if you are the instructor, you want to entice students to ask, “what is the purpose of the ‘else’, when we have handled all conditions (less than zero and greater than or equal to zero)?”. It would seem that the definition of absolute value of \(x\) as given above would cover all cases. In the world of programming (and mathematics) we have to pay close attention to the objects we are using. What if \(x = `Bob’\)? What is the absolute value of \(`Bob’\)? It’s undefined, at least with our definition of absolute value of \(x\). Thus, from a programming context, what should we do? What would happen? The answer: it depends on how our program executes. Either it will crash, or it will continue on merrily but with garbage output, or something else.
To drive home the point, consider this alternate definition of absolute value of \(x\).
$$
|x| = \left\{\begin{aligned}
&-x & if & x < 0\\
&x & & otherwise
\end{aligned}
\right.$$
What are the assumptions here? The use of the word “otherwise” is the equivalent of the “else” statement found in programming languages. How does this function work? One of the assumptions (and this was also an assumption in the previous definition) was that we are working with real numbers. Thus, if we can ensure that we have received a real number, this function is usable. If we cannot ensure that we have received a real number, this function will have undefined behavior. Because what does \(|Bob| = \)? \(Bob\) is certainly not less than zero, in fact, some programming languages may give an error when even trying to compare \(Bob\) to zero. Here’s what Python says:
>>> "Bob" < 0 Traceback (most recent call last): File "", line 1, in "Bob" < 0 TypeError: unorderable types: str() < int()
Notice it gave a TypeError
complaining that a string and an integer type were not orderable.
What does \(|x|\) look like in "code"? It depends on the language. In Python, it could look like (and seasoned programmers will know that there are shorter versions that exist):
def AbsoluteValue(x): if x < 0: return -x else: return x
And of course, the assumption in this code is that x
can be compared to zero.
Cooking
Cooking is another topic that lends itself to programming analogies. Anyone who has cooked something, elaborate or simple, has eventually learned the lesson of "make sure to have all the ingredients before cooking". We can think of this in terms of our "if-else" statement.
if (have all ingredients) AND (have all cooking tools) then: begin cooking else: do not begin cooking get all ingredients get all tools
Let's consider making a grilled cheese sandwich. What do we need in terms of ingredients and tools? I make grilled cheese with olive oil, bread, and cheese. I need a spatula, a pan of some sort, and a stove. Sometimes, I don't have a spatula and I brave it and flip the sandwich in progress by hand. Sometimes I don't have olive oil, so I use butter. So, here's a simple non-computer programming exercise. Make a flowchart to decide if we are ready to make a grilled cheese. And then, follow this flow chart in a real setting. Does the flowchart handle all possibilities and give a correct decision about whether or not to start cooking?
As a follow-up, even though the decision to start making the grilled cheese may have been correct. The sandwich could still end up looking like this:
This isn't the problem with the decision to cook, this is a problem with our sandwich making algorithm.
Algorithmic Thinking
The word "algorithm" to the non-programmer / non-mathematician is sometimes scary. The truth is, we use algorithms everyday. We just may not use the word. In fact, here is a "broad" definition of algorithm.
I already used Mathematics and Cooking for "if-else", but clearly both of these subjects utilize algorithms heavily. Cooking recipes are algorithms. Problem solving methods are algorithms. Here is how we can think about algorithms in an Art class.
Art Algorithms
Here is an algorithm for teaching about algorithms in an art class. Supplies needed are pencils, paper, a sturdy surface, and blackboard / whiteboard / projection display or the equivalent. A classroom with lights, etc. helps as well.
- Have students get into groups of two.
- Have one student face the blackboard / whiteboard / projection display or the equivalent.
- Have the other student have his/her back to the blackboard (or equivalent).
- The instructor draws a simple doodle on the blackboard (or equivalent).
- The student who is facing the blackboard (or equivalent) gives drawing instructions to the other student. The rules for drawing and giving drawing instructions are as follows: only verbal communication is allowed. No hand gestures, head bobbing movements, etc. are allowed. The student drawing may not lift the drawing pen / pencil / marker.
The goal is to replicate the instructor's doodle as closely as possible.
This is a simple example of algorithmic thinking / processing because it forces students to give unambiguous, explicit instructions. Computer programming requires this! Those loose intuitive ideas that we want executed need to be made explicit.
Functions
Another aspect of programming is the ability to write (small) functions (or methods) to encapsulate algorithms. Just like algorithms, we also think functionally. We do things and we say what we do by using verbs. I cook. I eat. I draw. I sleep.
Heck, we even define ourselves functionally!
I am a mathematician.
Computer programs must also do things. Calculate. Add. Subtract. Draw. The specifics of what that function does and how it does it is up to the programmer. Functions can be combined together to make larger functions. Again, mathematics, cooking, and art are all heavy users of functions.
Earlier, I gave an example of the absolute value function and how it can be codified. That is a function. It does something. Simplistically, it gives the distance a certain value is away from zero. The overly simplified explanation is that it makes negative numbers positive.
But let's think of other functions. More in terms of actions and not just mathematical. Obviously, there will be virtually no escape from thinking about algorithms and if-then clauses. Consider what to do when disaster strikes.
Disaster Preparedness
Disaster is an unfortunate reality of life. We all have experienced some form of disaster in some way, either directly or by hearing about it. An earthquake hits. A home burns down.
While the topic can be a bit macabre, we, nevertheless, have to plan in the event of disaster. Schools do one form of disaster preparedness in the form of fire drills. What is the process here? Have students demonstrate the algorithmic process of a fire drill. What events would trigger the fire alarm going off? How should the class organize? What happens if the class doesn't organize as per the plan (algorithm)? Do certain individuals have certain roles?
What about disaster preparedness in areas that are prone to heavy snowfall? What is the chain of command for alerting people about school cancellations. Who calls whom? What about areas prone to hurricanes or tornadoes?
From here, the instructor can extend and find age appropriate activities. For teenagers, what to do in a car accident, as a simple example. Call police. Get license and insurance information if in an accident with another vehicle. And so forth. Those are all actions, those are all functions.
And again, a flow chart is a good way to demonstrate the plan and all the decisions that have to be made.
Loops
Some tasks have to be done repeatedly. For this, there are certain looping procedures that are part of modern programming languages. These looping procedures are usually in the form of a for
loop, do-while
loop, while
loop, etc.
In mathematics, something like $$\sum_{n=1}^{100}2^{n}$$ can be codified using a for loop (or if we know the analytic solution, we can write that as well). In cooking, we may have a recipe that requires us to "stir regularly". When drawing, we may have to draw certain landscape elements many times. But let's consider other topics where we would use or find the use for a loop.
Here are a few examples worth discussing with students. Let them pick the one that interests them.
- single-crochet stitch
- a spider spinning a web
- money accruing interest in a fixed-rate bank CD
- that annoying tune that will play on repeat in your head
- There are some boardgames that are like "programming". One example is a game called "Robo Rally".
Wrapping It Up
I hope this article gave you a number of ideas of how to teaching elements of programming without the use of a computer. What I've given here is the tip of the iceberg. There's enough to write a book on this topic (want me to? find me a publisher that would be interested!).
Pingback: East Midlands West MathsHub Presentation | mathematicsandcoding
“As another example, when asked to write pseudocode that would swap the values of two variables a and b some students will say “make a equal to b and b equal to a”. And again, conceptually this is a correct idea for swapping, but if we thinking programmatically (not syntactically), this method of swapping fails since once we’ve “made a equal to b” we no longer know the original value of a. We remember what the original value of a was, but programmatically the student needs to recognize that a temporary variable of some sort is needed and the instructor needs to coax that out. The idea of a temporary variable is lost because we, to some extent, take our memory for granted.”
Of course, in Python you can:
a, b = b, a
(The temporary variable needed is handled under the hood.)
Yup, but even when I have taught Python, I hold off showing some of the syntactic sugar first since I do want my students to know what is going on under the good.
Nice post. I have definitely found it important to try and develop algorithmic thinking without the complication of syntax. Good pseudocode makes a big difference.