Lab 1: Part 4: Your first program

Now that you're familiar with our coding tools, let's write a very simple program to get used to how writing code works. What you will be doing is a bit like designing a board game or writing a recipe (and it's exactly like programming a robot): you are going to be writing a sequence of instructions for the computer to follow, that you can ask it to run through whenever you want. For now we will keep these very simple, but throughout this course you will be expanding your vocabulary of rules until you are building very complex programs that solve difficult problems.

We will start with a very simple math problem, which you could solve easily using a pen and paper: figuring out how tall a tree is by comparing shadows. Here's an illustration of the problem, showing the solution in one particular case:

A tree's shadow forms a triangle with the tree itself, and a stick will form a similar triangle. The stick is 1m tall and casts a 4m shadow, and the tree casts a 32m shadow, with x being the height of the tree. The ratio 1m:4m is equal to the ratio x:32m, and cross-multiplication gives 32=4x, which simplifies to 8=x, so the tree is 8m tall.

Credit: Emily Hinteregger via ShowMe

How can we set this problem up as a program?

First, we need to know what kinds of instructions we can give the computer.

Programming Rules

There are two things we can ask a computer to do: simplify an expression to get a value, or store a value (perhaps created by simplifying an expression) into a variable. If we want the computer to simplify an expression, we just write the expression we want it to simplify, including operators and possibly functions. There's one catch though: the computer cannot do partial simplification: it always requires that every variable which appears in the expression you give it already has a value.

That's where the other thing we can do comes in: storing values in variables. By writing a variable name followed by an equals sign (which we read "gets," not "equals") we can put the result of the expression on the right-hand side of the equals sign into the variable, replacing any old value it might have had.

Here's an example of both kinds of instruction in action:

x = 3
y = 4
z = x + y

The first two lines just store values, the third line simplifies an expression and stores the value. Notice that if this were math, we could equivalently do the following:

z = x + y
x = 3
y = 4

But if you try this in Python, you will get an error, because it executes instructions in-order from top to bottom, and when it encounters an expression to simplify, the values of each variable must already be defined at that point. This also allows us to do weird things that would make no sense as math, like this:

x = 4
x = x + 1

In mathematics, that's a contradiction. But in programming, it's two valid instructions:

  1. Store 4 in x.
  2. Simplify "x + 1" to get a value, and store that value in x.

The second step here will use the old value of x when it simplifies the expression, and so the new value of x will be 5. In math, there is no concept of an "old" or "new" value for a variable, but in programming, variables are allowed to have different values at different points in time.

Note that in addition to operations like +, we can use functions. Python has a limited set of built-in functions, but offers a way of importing libraries of functions that will give you access to many more, which we'll see in the next part.

You may have noticed that if we type in the code above into Thonny and hit the "run" button, we don't see anything happening. This is because we need to use a function called print to display things when our program runs. Now normally, a function would be used as part of an expression to give us a value, but print doesn't have a value, instead it has a "side effect:" whenever you evaluate it, the value that you gave it will appear in the program's output (which you can see in the Thonny shell when you run the program). Here's an example:

x = 3
y = 4
z = max(x, y) + 1
print(x)
print(y)
print(z)

We're using the print function to show the values of x, y, and z, and we're also using the max function as part of an expression (which Python simplifies as you'd expect). If you paste this code into your file and run it, you should be able to see the following printed results:

3
4
5

The essence of programming is using the computer's ability to simplify (or really, evaluate) expressions and to store values in variables (and update them) to solve problems, from simple math problems like the one we're about to tackle, to building complex applications that change what's possible in the world at a global scale!

The height of the tree

So back to our original problem: how could we solve the height of the tree using a program? If it were a math problem, we might write something like this to capture the fact that the similar triangles force the ratio of height-to-shadow to be the same for both the tree and the stick:

h1 / s1 = h2 / s2

Note that we use '/' in Python for division, and we can't easily write subscripts. We could, (and should) use more descriptive variable names, however (programmers tend to use long variable names, rather than single-letter variables like in math, because we end up with a lot more variables and have to remember what they mean more often).

stickHeight / stickShadow = treeHeight / treeShadow

Now again, if this were math, we could complete the specific situation by defining values for some of the variables:

stickHeight / stickShadow = treeHeight / treeShadow
stickHeight = 1
stickShadow = 4
treeShadow = 32

However, computers are actually pretty bad at math, despite what you may have heard! There are two problems with the 'code' above that mean that it doesn't fit the rules of programming we just covered. Before reading further, can you spot them?


Remember that our two types of instructions are storing values in variables and simplifying expressions? The first problem with the 'code' above is that it expresses an equation that relates multiple variables, rather than assigning a value to a single variable. The computer actually doesn't know how to solve an expression for a particular variable. In other words, the only thing that can appear on the left-hand side of an equals sign is a single variable, which will be updated. If you have multiple variables or a complex expression on one side of an equation, you need to solve it for the computer, so that only one variable is on the left-hand side. That would look like this (note that we use '*' for multiplication in Python):

treeHeight = treeShadow * stickHeight / stickShadow
stickHeight = 1
stickShadow = 4
treeShadow = 32

But there's one more problem: we said above that the value of every variable must be defined before we include it in an expression (computers are so picky!). So to turn this math problem into a program, we actually need it to look like this:

stickHeight = 1
stickShadow = 4
treeShadow = 32
treeHeight = treeShadow * stickHeight / stickShadow
print(treeHeight)

Note that we've added a print function to make sure the program actually shows us the answer it gets! If you copy/paste this program into Thonny and run it, it should print 8.0, which is the correct solution.

So was there any point to this? Actually, by encoding things as a program, we can now have the computer do the math for us, and we can plug in different values for the variables! Try changing the stickHeight, stickShadow, and treeShadow variable values and seeing what results you get.

We had to do the work of solving the equation for the variable we're interested in, and making sure that all the other variables were defined beforehand, reducing a real math problem to just a series of steps that you could plug into a calculator. But we can write down those steps in the computer, and then ask it to carry them out again and again, giving it different inputs.

Working with text

There's one more important concept we need to introduce today: working with text. In Python, we call text "strings" (as in "a string of letters in a row"). We can define text within a program by surrounding it with quotation marks (either single or double quotes work, but you have to be consistent at both ends of the string). Strings can be stored in variables, and we can also use '+' to combine strings (including strings that come from variables) into longer strings. Here's a simple program that uses text:

name = 'Peter'
print("Welcome to CS111, " + name)

Note that in the string "Welcome to CS111, ", we included a space before the ending quotation mark so that when we combine it with the name, there will be a space after the comma. Also notice how we used single quotes for the name that we stored in the variable, and double quotes for the message; either is fine as long as you end each string with the type of quote that it started with.

In addition to using '+' to combine strings, we can also use '*' to repeat them, like this:

print('HA'*8)

Python's ability to process text allows us to do a lot of interesting things that go well beyond solving math problems, and we'll see more of that next week.

Text and Numbers

What happens if we try to add a string and a number together? Let's try it:

print("two" + 2)

We get an error:

Traceback (most recent call last):
  File "/Users/pmawhort/tmp/lab01.py", line 19, in <module>
    print("two" + 2)
TypeError: can only concatenate str (not "int") to str

Errors are an important part of programming, and you should try to read them when you get them, even though they may be quite cryptic at first. Whenever you give Python an instruction that it doesn't understand, or ask it to do something that it isn't capable of, it will give you an error message like the one above. The error message is at the bottom, and above that, it will tell you (and show you) which line of the program the error occurred on (and what file it was in). We will learn more about errors soon.

The issue with the code above is that the meaning of "two" + 2 is ambiguous: did we intend "two" to refer to the number 2? If so, why did we write it as a string and not a number? Or did we intend 2 to refer to the digit '2' and not the number 2? If so, why did we write it as a number.

Internally, Python stores each value as a certain "type," and there are rules that apply to each type. The types we have used so far are int (integers), float (non-integer numbers), and str (strings of text). You can use the type function to see the type of a value, for example:

print(type(5))
print(type(5.3))
print(type("five"))

We can actually get two different results using the same operator with different types of value, like this:

print(2 + 2)
print('2' + '2')

In the first case, we're asking Python to add numbers, in the second, we're asking it to join together (i.e., 'concatenate') strings. Note that we can use the int, float, and str functions to convert between types when appropriate. For example, str(22) would be the string '22', while int('22') would be the integer 22. But Python isn't smart enough to convert int('two') to the number 2, and trying that will give you an error. If we want to use text and numbers together (for example when printing messages that include numbers) we'll have to do some conversion. Here's an example:

stickHeight = 2
stickShadow = 4
treeShadow = 32
treeHeight = treeShadow * stickHeight / stickShadow
print("The height of the tree is: " + str(treeHeight))

One last tip: the conversion functions are functions that create a result value; they cannot be used to change what's in a variable to a different type. So the following code doesn't work:

x = 5
str(x)
print("X is: " + x)

Instead, if you want to change what's in a variable, you need to use 'gets' to store a new value, like this:

x = 5
x = str(x)
print("X is: " + x)

Armed with this knowledge of variables, expressions, and types, you're ready to move on to the next part of the lab and write a program that you get to design!

Table of Contents