CodeRigor

LESSON

Write functions and finish a complete program

Name a step as a function with parameters and a return value, then build a complete interactive program from variables, input, decisions, loops and functions.

You have been calling functions since the first lesson: print, io.read, tonumber. In this lesson you write your own, and then put everything from this unit together in one complete program.

A function is a named step

A function is a block of statements with a name. Writing the block and naming it is called defining the function. Running it is called calling it.

Lua
local function show_rule()
    print("--------------------")
end

show_rule()
print("Today's menu")
show_rule()

This prints a line of dashes, then Today's menu, then another line of dashes.

The first three lines define the function. They start with local function, then the name, then a pair of round brackets, and they finish with end. The statements in between are the function's body. As with variables, local keeps the name to this file. Defining a function runs nothing: no dashes appear until a later line calls it with show_rule().

Lua reads the file from top to bottom, so a function must be defined above the first line that calls it.

Functions are worth writing for two reasons. A step you need several times is written once. And a well-chosen name says what a group of lines is for, which makes the rest of the program read like a list of steps.

Parameters let a function work on different values

A parameter is a variable in the function's brackets. It gets its value from the argument each time the function is called.

Lua
local function greet(name)
    print("Hello, " .. name .. "!")
end

greet("Ada")
greet("Sam")

This prints Hello, Ada! and then Hello, Sam!. In the first call the parameter name refers to "Ada"; in the second, to "Sam". A function can have several parameters, separated by commas. The arguments are matched to them in order.

return hands a value back

greet shows something on the screen. Many functions should instead work something out and hand the answer back to the line that called them, the way tonumber hands back a number. The statement return does that.

Lua
local function area(width, height)
    local result = width * height
    return result
end

local floor = area(3, 4)
print(floor)
print(area(2, 5) + 1)

This prints 12 and then 11. A call such as area(3, 4) is an expression: when it finishes, the call is replaced by the returned value. So you can store it in a variable, or use it in a calculation, as the last line does.

What happens when line 6 calls area(3, 4)
start / 5 ⇄ code
The arguments are copied into the parameters, the body runs, and return sends one value back to the place of the call.
What happens when line 6 calls area(3, 4)
The arguments are copied into the parameters, the body runs, and return sends one value back to the place of the call.

Three things to know about return:

  • It ends the function at once. It must be the last statement of its block, directly before an end or an else.
  • A function that reaches its end without a return hands back nil.
  • result, width and height exist only while the function runs. The rest of the program cannot see them, and that is good: a function's working variables cannot clash with names elsewhere.

print or return?

They look similar when you try a function out, and they are completely different.

  • print shows text to the person at the screen. The program itself gets nothing back.
  • return gives a value to the program. Nothing appears on the screen unless some line prints it.
Lua
local function double_shown(n)
    print(n * 2)
end

local function double_returned(n)
    return n * 2
end

local a = double_shown(5)
local b = double_returned(5)
print(a)
print(b)

This prints 10, nil and 10. The first 10 is printed by double_shown while it runs; it returns nothing, so a is nil. double_returned prints nothing, and b is 10.

A useful rule: functions that work something out should return it, and leave the decision to print to the code that called them.

Functions can contain everything you know

The body of a function is ordinary code: variables, if chains, loops, calls to other functions. A return inside an if chain gives a different answer on each path:

Lua
local function ticket_price(age)
    if age < 12 then
        return 5
    elseif age >= 65 then
        return 6
    else
        return 9
    end
end

print(ticket_price(8))
print(ticket_price(30))
print(ticket_price(70) + ticket_price(70))

This prints 5, 9 and 12.

A complete program

Here is a whole interactive program that uses every lesson of this unit: output, variables, input and conversion, a decision, a loop, and a function. Read it from the top and say what each part does before you read the explanation.

Lua
-- A three-question quiz on the 7 times table.

local function mark(answer, correct)
    if answer == correct then
        return "Right!"
    else
        return "Not quite: it is " .. correct .. "."
    end
end

print("Three questions on the 7 times table.")

local score = 0
for n = 1, 3 do
    io.write("What is 7 x " .. n .. "? ")
    local answer = tonumber(io.read("l"))
    local verdict = mark(answer, 7 * n)
    print(verdict)
    if verdict == "Right!" then
        score = score + 1
    end
end

print("Score: " .. score .. " out of 3")

With the answers 7, 15 and 21 the session is:

Text
Three questions on the 7 times table.
What is 7 x 1? 7
Right!
What is 7 x 2? 15
Not quite: it is 14.
What is 7 x 3? 21
Right!
Score: 2 out of 3

Paste it into the Lua playground with three answers in the Standard input box and try it.

The structure of the quiz program
start / 4
Definitions first, then set-up, then a loop in which each iteration asks, reads, calls the function, prints and counts. The summary comes after the loop.
The structure of the quiz program
Definitions first, then set-up, then a loop in which each iteration asks, reads, calls the function, prints and counts. The summary comes after the loop.

Notice how the work is divided. mark decides and returns a string; it does not print and does not read input. The loop does the talking: it prompts, reads, prints. Splitting a program this way lets you check the deciding part by itself, by calling mark(15, 14) and looking at what comes back.

Two errors you will meet

Calling a function above its definition.

Lua
print(double(4))

local function double(n)
    return n * 2
end
Text
/usr/bin/lua: solution.lua:1: attempt to call a nil value (global 'double')
stack traceback:
	solution.lua:1: in main chunk
	[C]: in ?

You met this message in the first lesson for a misspelt name. The cause here is order: when line 1 runs, Lua has not yet reached the definition, so the name double still refers to nothing. Move the definition to the top.

Too few arguments.

Lua
local function area(width, height)
    return width * height
end

print(area(3))
Text
/usr/bin/lua: solution.lua:2: attempt to perform arithmetic on a nil value (local 'height')
stack traceback:
	solution.lua:2: in local 'area'
	solution.lua:5: in main chunk
	[C]: in ?

Lua does not complain at the call. A parameter with no argument is nil, and the program stops later, inside the function, when line 2 tries to multiply by it. This is where the stack traceback earns its place. Read it from the top: the error happened on line 2, in the function area, which was called from line 5. The line to fix is line 5, the call with a missing argument.

A function that forgets its return causes a similar surprise: the call gives nil, and the error appears on the line that uses the result.

What you can do now, and where to go next

You can define functions with local function, pass arguments to parameters, return values, tell print from return, and read a traceback that passes through a function. With variables, input, decisions and loops, that is enough to write complete console programs, and the capstone exercise asks you for one: a number-guessing game.

When you have finished it, you are ready for the next unit of this course. It starts with values, types and truthiness, and the course goes on to tables, Lua's tool for holding many values at once, then strings and patterns, modules, and more. It moves faster than this unit and assumes exactly what you now know.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Starts at 'Functions' (28:26), about a minute on defining and calling a function. Stop at 'Return Multiple Values' (29:25), which goes beyond this lesson.