Programming foundations · Module 1
What a program is, and what happens when you run it
Six lines of text, one command, three lines on screen. This page follows one small program from the file you save to the output you see — and shows you exactly where a missing bracket gets caught, and where it does not.
Run the pipeline one stage at a time →01 The idea
Instructions in order, and a file that is only text
A computer does not work out what you meant. It carries out instructions, one at a time, in the order it is handed them. A program is that list of instructions, written down. When you write print(edge) you are not asking for something — you are adding one more step to a list that will be worked through from the top.
The catch is that the list you write is not the list the machine runs. You type characters into a file, and a file is text. It is the same kind of thing as a shopping list, and just as unable to do anything by itself. Something has to read your text, check that it is written in a form it can understand, and turn it into instructions a processor can carry out. That reading step is where an entire family of errors lives, and knowing it is there is the difference between a message that unblocks you and a message that scares you off.
02 Execution trace
Six lines, and the order they actually run in
Here is the whole program. It prints a name card: a row of dashes, a name, the same row of dashes again. Save it as card.py and run it.
card.py · what you write
def card(name): edge = "-" * 6 print(edge) print("| " + name) print(edge)card("Asha")
terminal · what you see
------| Asha------
Now the trace. One row per statement executed, in the order it executes. The left column is the line number. The three boxes are the two values the program creates — name and edge — and a running count of lines put on screen. A rose box is a value that just changed; a green box is settled and final.
Read the left column downwards: 1, 6, 2, 3, 4, 5, end. The order the lines run is not the order they are written, and that is normal rather than exceptional. Line 1 only stores the block. Line 6 is the first line that does anything, and it sends the machine backwards into the block that line 1 just stored.
Notice the other half of the trace too. Six lines run, and only three of them put anything on screen. Storing a block, binding a name and building a string are all real work, and none of them are visible. Beginners lose hours to a program that is running perfectly and was simply never told to print anything.
03 Anatomy
Reading the file, then reading the error
The same six lines, annotated. Four things make up any source file: statements, blocks, whatever marks where a block starts and stops, and one entry point where execution begins.
def card(name): # header: opens a block, ends with a colon edge = "-" * 6 # statement, indented, so it is inside the block print(edge) # statement print("| " + name) # statement — the widest line in the block print(edge) # last indented line, so the block ends herecard("Asha") # left margin: top level, so this call is what runs the block
Indentation is not decoration. In Python those four spaces are the only thing saying "this line belongs to card". Delete the indentation on line 5 and it stops being part of the card and becomes a top-level statement that runs on its own. C, Java and JavaScript do the same job with { and } and treat indentation as a courtesy to humans — but every language has some marker, and it is never optional.
Defining is not running. Line 1 prints nothing. It stores the four indented lines under the name card and moves on to line 6. A block sits there unused until something calls it, which is why line 2 runs third rather than second.
The entry point is where execution begins, and there is exactly one. Python starts at the first top-level line and works down, so here execution starts at line 1 and the first line that makes anything happen is line 6. C and Java instead look for a function named main and start there. Either way the machine never starts at "the line that looks most important".
Now the part that actually unblocks you. Everything that can go wrong falls into three families, and the family tells you where in the pipeline it was caught — which in turn tells you how much of your program ran before it stopped.
| Error family | Caught when | How it announces itself |
|---|---|---|
| Syntax error the file is not written legally | before line 1 | A file name, a line number, a caret under the spot, and a last line naming the fault. Your program produces no output at all. |
| Runtime error legal code, impossible action | mid-run | Everything printed up to that instant is already on screen, then a traceback listing the calls and a last line naming the exception. |
| Logic error legal code, wrong idea | never | A clean run and an exit code of 0. Nothing is reported, because nothing is broken. The output is simply not what you wanted. |
Here are the first two, produced by the same six-line program with one character changed each time. Look at what is above the message as much as at the message itself.
Syntax error · nothing ran
File "card.py", line 4 print("| " + name ^SyntaxError: '(' was never closed
Runtime error · one line already printed
------Traceback (most recent call last): File "card.py", line 6, in <module> card("Asha") File "card.py", line 4, in card print("| " + nme)NameError: name 'nme' is not defined
Read the last line first. It carries the two things you need: a type and a message. SyntaxError plus '(' was never closed. NameError plus name 'nme' is not defined. Everything above the last line is location. Most beginners read from the top, meet a wall of file paths, and give up one line before the useful part.
In a traceback, the top is the oldest call and the bottom is the newest. On the right, line 6 is listed first because that is where the call started, and line 4 is listed last because that is where it broke. The line you edit is almost always the bottom one. The right-hand run also got one line onto the screen first — that dash row above the traceback is proof the program really did start.
The line named is where the trouble started, not where the reader noticed it. On the left the caret sits on line 4 because that is where the bracket opened — but nothing was noticed until the end of the file, which is why lines 5 and 6 were swallowed as if they were still inside that bracket. A missing quote or a missing colon is kinder: Python can tell at once, so it names that exact line. Either way, check the line named first, then the line above it.
05 Cheat sheet
The four stages, and what fails at each
| Stage | What happens | If it fails |
|---|---|---|
| 1 · Source | You type text and save it as card.py. It is characters on a disk, nothing more. | cannot fail |
| 2 · Check | A compiler or interpreter reads the whole file and verifies its grammar. Nothing is calculated here. | SyntaxError — zero output |
| 3 · Run | Statements execute in order from the entry point, jumping into blocks when something calls them. | NameError and friends — whatever had already printed, then a traceback |
| 4 · Output | Whatever you printed is on screen, and an exit code goes back to the operating system. | wrong answer — a logic error, and the exit code is still 0 |
06 Where & why
The same four stages, in the tools you will actually use
The stages do not change between languages. What changes is how many commands you type and what the error messages are called. Once you can see the pipeline, a new language is mostly new vocabulary.
One command does the whole pipeline. Python parses your entire file into bytecode first, then runs it. That single fact is why a missing bracket on line 4 stops line 3 from printing, which surprises people who think an interpreter runs line by line.
Two commands, because the stages are split across two tools. The first checks and translates and produces a file called card; the second runs it. If the check fails you never get that file at all, so there is literally nothing to run.
Same split: javac checks and produces Card.class, and java runs it on the JVM. This is why Java people say "compile-time error" and "runtime exception" as two separate phrases — they happen at two separate commands.
The browser parses and runs your script as the page loads, and its error messages go to the Console tab behind F12. They read exactly like the ones in section 03: a type, a message, a file and a line. A blank page usually means a syntax error, not a network problem.
07 Interview questions
Say these out loud
These come up in first-round screens and in viva. The error-message question is the one that tells an interviewer whether you have actually written code or only read about it.
What is a program?
What actually happens between saving a file and seeing output?
Why does a syntax error on the last line stop the first line from printing?
What is an entry point?
How does a language know which lines belong to a block?
Syntax error versus runtime error — what is the difference?
What is a logic error, and why is it the worst kind?
You hit an error message you have never seen. Walk me through what you do.
Compiled or interpreted — what is the real difference?
Is Python compiled or interpreted?
What does an exit code of 0 mean?
08 Practice problems
Predict first, then run
Write your answer down before you touch a keyboard. Being wrong on paper and finding out why is the whole exercise; running it first skips the part that teaches you something.