Errors and pcall

So far, the errors have come from Lua itself: calling nil, adding nil… Your own functions can report errors too. When a function gets values it can't work with, it's better to stop with a clear message than to carry on with a wrong result. That's what error is for:

local coins = 20

local function buySeeds(price, bags)
    local cost = price * bags
    if cost > coins then
        error("Not enough coins")
    end
    coins = coins - cost
    return coins
end

print(buySeeds(2, 5))
print(buySeeds(5, 4))
print("Done")

This prints:

10
main.lua:6: Not enough coins
stack traceback:
	[C]: in function 'error'
	main.lua:6: in local 'buySeeds'
	main.lua:13: in main chunk

error stops the program, just like an error from Lua: Done is never printed. Lua puts main.lua:6: in front of your message: the line where error was called. The traceback shows how the program got there; read it from the bottom: the main program called buySeeds on line 13, and on line 6, buySeeds called error. ([C] means a function built into Lua, which is written in the C language.) When you don't want the position in the message, pass 0 as the second argument: error("Not enough coins", 0).

“If this isn't true, stop with an error” is such a common check that it has a shortcut: assert(condition, message). When the condition is true, assert does nothing; when it's false or nil, it ends with the message:

local function plantSeeds(crop, plots)
    assert(plots > 0, "Plant at least one plot")
    print("Planting " .. crop .. " on " .. plots .. " plots")
end

plantSeeds("carrot", 3)
plantSeeds("wheat", 0)

This prints:

Planting carrot on 3 plots
main.lua:2: Plant at least one plot

Sometimes an error shouldn't end the whole program. Emma can't afford the pumpkin seeds, but she still wants to buy the others. pcall (protected call) calls a function and catches its error. Give it the function and then its arguments: pcall(buySeeds, 5, 4) calls buySeeds(5, 4). pcall returns several values: when everything goes well, true and whatever the function returned; when there's an error, false and the error message. Either way, the program carries on:

local coins = 20

local function buySeeds(price, bags)
    local cost = price * bags
    if cost > coins then
        error("Not enough coins")
    end
    coins = coins - cost
    return coins
end

print(pcall(buySeeds, 2, 5))
local ok, result = pcall(buySeeds, 5, 4)
if ok then
    print("Coins left: " .. result)
else
    print("Error: " .. result)
end
print("Done")

This prints:

true	10
Error: main.lua:6: Not enough coins
Done

The usual way is the second one: store the values in ok and result, and decide by ok what result is. A typical mistake is writing pcall(buySeeds(5, 4)). With the parentheses after buySeeds, Lua calls the function right away, before pcall, so its error isn't caught. As with any function you pass to another one, pass the function itself and its arguments separately.

Instructions

Emma's coins drop below zero. In buySeeds, before she pays, end with error("Not enough coins for " .. crop, 0) when cost is greater than coins. Then the second purchase would stop the whole program, so call all three purchases through pcall and print what it returns, for example print(pcall(buySeeds, "carrot", 2, 5)). The program prints:

true	10
false	Not enough coins for pumpkin
true	6

Emma can't buy zero bags. At the start of buySeeds, add assert with the condition bags > 0 and the message "Buy at least one bag". Then, at the end of the program, print pcall(buySeeds, "corn", 3, 0). The new line is false and the message with its position, for example:

false	main.lua:5: Buy at least one bag

Write a function tryToBuy with the parameters crop, price and bags. It calls buySeeds through pcall and stores the results in ok and result. When the purchase works, it prints Bought … seeds, coins left: …; otherwise, it prints Can't buy … seeds: and the error message. At the end of the program, call tryToBuy("strawberry", 4, 1) and tryToBuy("potato", 3, 2). The program ends with:

Bought strawberry seeds, coins left: 2
Can't buy potato seeds: Not enough coins for potato

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

10/11