The divider from Unit 2 does the same thing every time. That is fine for a divider. Most jobs are not like that: you want the same work done to a different value each time.
So you give the job something to work on.
Handing a value in
Put a name in brackets after the job’s name. That name stands for whatever the caller hands over:
DEFINE greet(who)
SHOW "Hello, ", who
END
CALL greet("Sam")
CALL greet("Ada")Hello, Sam Hello, Ada
One job, two results. Inside greet, the box who holds whatever came in with the call:
"Sam" the first time, "Ada" the second.
That box belongs to the job. It holds its value while the job runs and means nothing
outside, so a who anywhere else in your program is a different box that happens to share
a name.
Handing a value back
A job can also give an answer. RETURN hands a value to whoever called, and the job stops
there:
DEFINE double(n)
LET n = n * 2
RETURN n
END
LET x = double(5)
SHOW x10
double(5) runs the job with n set to 5, and the RETURN sends 10 back. That answer
lands where you wrote the call, so LET x = double(5) puts 10 in x.
The assignment changes the job’s local n before it returns.
Notice the two shapes are different on purpose. CALL greet("Sam") does a job and expects
nothing back. You use double(5) for its answer, so it sits where a value belongs.
The caller keeps its own value
Our notation passes a copy of a numeric value. Reuse double with a caller
variable that also happens to be called n:
LET n = 5
LET result = double(n)
SHOW n, " and ", result5 and 10
At the call, the caller’s n is 5. The job gets its own n, also 5. Changing
that local copy to 10 leaves the caller’s n at 5. The returned 10 is stored
in result. To replace the caller’s value, we would write LET n = double(n).
With n = 3, what do LET result = double(n) and LET n = double(n) leave in the caller?
The first leaves n = 3 and stores 6 in result. The second puts the
returned 6 into the caller’s n. Updating the local parameter and assigning
the returned value in the caller are separate steps.
This example uses numbers. Do not infer how a real language passes a list, shares memory or makes copies from the spelling of a parameter name.
Say what the caller can rely on
Compare greet with double. Before tracing either call, predict which one changes
the display and which one supplies a number we can use in another calculation.
Compare their promises
| Job | Input | Result for the caller | Other effect |
|---|---|---|---|
greet |
A name | No returned value | Displays a greeting |
double |
A number | Twice that number | Does not print anything |
We can check double(0) without drawing a screen: it should return 0. Changing it
to print the answer instead would break LET x = double(5), even if 10 looked right
on screen. The caller needs the result, not just a visible effect.
This small agreement is a contract: what goes in, what comes back and what else changes. Later, a drawing or sound routine also needs to say which state it changes and whether its work is finished when it returns.
Our pseudocode gives parameters local names. A machine language may pass them in
registers or shared memory instead. Sinclair BASIC’s GO SUB does not create these
local parameter boxes, and its RETURN resumes the caller without returning an
expression. We carry the idea across, then explain how that language implements it.
For a concrete contrast, Write the repeated job once
traces Sinclair BASIC’s numbered GO SUB and RETURN. Read its return-point
explanation without running the preceding game. BASIC’s ordinary variables are
shared with the subroutine; it does not supply this example’s local parameter
copy or expression result automatically.
When it’s wrong, see why
- The job always does the same thing. You named a value in the brackets but used a different name inside the job. The name in the brackets is the one that holds what came in.
- You get nothing back. The job has no
RETURN, or the program reached theENDwithout passing one. A job with nothing to hand back is one youCALLinstead. - You called it without the value it needs.
CALL greet()does not meet this job’s contract: we must supply a name. Our notation does not invent a value forwho; a real language defines how it reports or handles a missing argument.
What you’ve learnt
- A job can take a value: the name in brackets holds whatever the caller hands over.
RETURNhands a value back, and the answer lands where you wrote the call.- A job you
CALLdoes something. A job you use for its answer goes where a value goes. - The names inside a job belong to the job.
What’s next
We now have a useful set of ideas for building programs: instructions, order, output, memory, input, arithmetic, decisions, loops, lists and named jobs. One thing remains, and it is the most useful of all. In Unit 4 we find out what to do when a program does the wrong thing.