Before You Begin: The Abstractions CS Assumes You Already Have
School computing teaches a language. University computer science teaches what the language means; what executes, what it costs, and how to reason about a program without running it. The transition fails when a student can write code that works but cannot say why it works, cannot predict how its cost grows, and cannot prove anything about it.
This page rebuilds the four abstractions everything else assumes: functions as reusable units, boolean logic as the algebra of decisions, execution as a state machine you can trace by hand, and growth of cost as the first idea of complexity. Every term is defined before use, and every claim is checkable by hand-tracing the code shown.
Intuition
Section titled “Intuition”A program is a precise description of a process; so precise that a machine can follow it, and so precise that you can predict what it does without a machine. That second ability is the subject. The skill is not syntax; syntax is interchangeable. The skill is holding a small machine in your head: these variables have these values, this loop runs this many times, this condition is true on exactly these inputs. Everything on this page is practice at that.
1. Functions: naming a computation
Section titled “1. Functions: naming a computation”Definition. A function takes inputs (arguments), performs a computation, and returns exactly one output (return value). Calling a function executes its body with the arguments bound to its parameters.
function square(n) { return n * n;}square(4) returns 16. The point of a function is not brevity; it is that the computation now has a name, can be reasoned about once instead of everywhere it appears, and a bug in it is fixed in one place.
Definition. A pure function depends only on its arguments and has no effect on anything else. square is pure. A function that prints, writes a file, or modifies a global variable is impure.
Why purity matters. Pure functions can be reasoned about by substitution: square(4) + square(3) can be replaced by 16 + 9. Impure functions cannot - each call may do something different. Tests, refactoring and optimisation all get easier as functions get purer, and the university course will assume you default to purity.
Scope. A variable defined inside a function exists only inside it. Two functions can each have a variable called total without colliding; the names live in separate scopes.
2. Boolean logic
Section titled “2. Boolean logic”Definition. A boolean expression evaluates to true or false. The three operators: and (both), or (at least one; inclusive), not (negation).
a | b | a and b | a or b | not a |
|---|---|---|---|---|
| T | T | T | T | F |
| T | F | F | T | F |
| F | T | F | T | T |
| F | F | F | F | T |
De Morgan’s laws.
not (a and b) == (not a) or (not b)not (a or b) == (not a) and (not b)Proof by truth table. The two sides agree on all four rows of combinations - checking all four is the entire proof, and for a two-variable boolean expression checking all four rows is a complete proof, not a sample.
Short-circuit evaluation. a and b does not evaluate b when a is false; a or b does not evaluate b when a is true. This is load-bearing in real code: if (i < len(a) and a[i] == x) is safe because short-circuiting prevents a[i] from being evaluated when i is out of range. Reversing the order breaks the program.
The equivalence move. “Not (it rained and it was cold)” equals “it did not rain, or it was not cold”. Translating between English and boolean algebra; in both directions; is the skill every conditional statement you write depends on.
3. Execution: the machine you can trace
Section titled “3. Execution: the machine you can trace”Definition. A variable is a name bound to a value; assignment rebinds the name. A loop repeats a block while a condition holds.
Tracing is the core skill. Take this; a loop computing the sum of the first positive integers:
total = 0i = 1while i <= n: total = total + i i = i + 1For n = 4, the trace is a table:
| step | i | total |
|---|---|---|
| start | 1 | 0 |
| 1 | 2 | 1 |
| 2 | 3 | 3 |
| 3 | 4 | 6 |
| 4 | 5 | 10 |
The loop exits when i is 5, and total is 10; which is , as the closed form predicts. Tracing converts “I think this works” into “I know what this does on this input.” The next step; proving it works on all inputs; is induction, and the loop’s variable i is exactly the induction variable: total is at the top of every iteration, which is the invariant the mathematics site proves.
What executes is not what you meant. A common off-by-one: while i < n versus while i <= n differ by one iteration; a trace table exposes the difference immediately. Reading code is not enough; trace it.
4. Growth of cost: the first idea of complexity
Section titled “4. Growth of cost: the first idea of complexity”Definition. The running time of a program on an input of size is the number of elementary operations it executes, as a function of .
Count operations in this search:
found = falsefor i in 0 .. n-1: if a[i] == target: found = trueThe comparison runs times; each iteration is a constant amount of work, so the total is operations; linear in .
Compare binary search on a sorted list: each step halves the remaining range, so after steps remains, and the loop ends when , i.e. ; logarithmic.
Definition (asymptotic notation, informally). A program is if its running time is at most a constant times for large . Linear search is ; binary search is ; the nested-pair loop over items is .
Why it is the first idea of complexity. Constants do not matter at scale: an algorithm beats an one for large no matter how much slower its constant factor, because . The difference between linear and quadratic search on a billion items is the difference between a step and a lifetime; roughly operations against .
The university course will define with quantifiers; ; and prove the properties. What this page asks is that you can count the iterations of the loops you write and say what function of they are.
5. Self-test
Section titled “5. Self-test”- Write the boolean expression for “x is between 1 and 10 inclusive”, then its negation without
notaround the whole thing. (§2) - Trace the loop in §3 for
n = 3. What istotalat exit? (§3) - Why does
if (i <= len(a) and a[i] == x)risk an error thatif (i < len(a) and a[i] == x)does not? (§2) - An algorithm does operations. Is it , , or both? What does “both” mean here? (§4)
- How many times does the innermost statement run in a loop over from 1 to containing a loop over from 1 to ? (§4)
Answers. (1) x >= 1 and x <= 10; negated by De Morgan: x < 1 or x > 10. (2) total = 6; the loop adds 1, then 2, then 3. (3) When i == len(a), the index a[i] is out of range; with i < len(a) first, short-circuiting prevents the second test from running. Reversed, the second test runs on an invalid index. (4) ; the definition only requires at most a constant times eventually, and for . It is also : big-O is an upper bound, not a tight one. The tight class here is . (5) ; the loop trace from §3, generalised.
Where to go next
Section titled “Where to go next”- Algorithms and Data Structures; growth of cost, made a subject.
- Computer Networks; the layered abstractions this page’s “what executes” thinking generalises to.
- Discrete Mathematics; the logic of §2, with proofs.