Lesson 9 of 10
Raising and catching errors
- 13 min
- 6 checks
- 3 hints
- Go to task
Goal
Raising with error, catching with pcall, and returning nil with a message
Explanation
Lua has two ways of dealing with failure. The first is for expected failure, like a player trying to buy something without enough gold. Here the function doesn't stop with an error. Instead it returns nil along with a message: return nil, "Not enough gold". The caller then checks the result: local left, err = withdraw(gold, 30), followed by if not left then print(err) end. That's how io.open works in the standard library.
The second is for faults that should never happen in the first place, like negative damage coming from buggy code. error("Invalid damage") stops execution and passes the error up to the caller, then to that function's caller, and so on until something catches it. If nothing does, it stops the whole script. On a game server, that means one buggy event stops everything after it.
You catch an error with pcall(f, ...). It calls f with the arguments: if the call succeeds, it returns true followed by the results, and if it raises an error, it returns false and the error message. xpcall(f, handler, ...) works the same way, but it first passes the error to handler, for example debug.traceback, which tells you where the error happened. The common mistake is writing pcall(damage(100, -5)): here damage is called before anything reaches pcall, so nothing gets caught.
Your task
Write withdraw(gold, amount), which returns what's left, or nil and a message if amount is more than gold. Then write damage(hp, amount), which raises an error with error if amount is negative, and otherwise returns the health after the damage without going below zero. Finally, write safeDamage(hp, amount), which calls damage through pcall and returns the result if it succeeds, or nil and the error message if it fails.
Checks
6 checks- withdraw returns what's left
- Without enough gold it returns nil and a message
- damage lowers health and doesn't go below zero
- damage raises an error for negative damage
- safeDamage returns the new health
- safeDamage turns the error into nil and a message without raising it