LessonsAdvanced: Bigger programsLesson 36

Handling errors

Catch errors with try and catch so a program can recover, raise your own with throw, and know which commands report problems in the result instead.

  • Advanced
  • Lesson 36 of 83
  • About 10 minutes
  • 8 examples

When something goes wrong

Some mistakes are found before a script runs: a misspelled end if, a missing quote. Others only show up as it runs: a division by zero, a number that turns out to be a word, a file that is not there. These runtime errors stop the handler, and every handler that called it, and xTalk reports where it happened.

A mistakeIt stops with an error on line 2
put "ten" into tCount
put tCount + 1

That is the right thing while you are writing a program. In a finished one, you would rather the program noticed the problem and dealt with it.

Catching errors: try and catch

Put the lines that might fail between try and catch. If any of them raises an error, xTalk jumps straight to the lines after catch, and the program carries on after end try:

ExampleRun it in the playground
try
   put "ten" + 1 into tAnswer
   put "this line is never reached"
catch tError
   put "Something went wrong"
end try
put "and the program carries on"
Output
Something went wrong
and the program carries on

The variable after catch receives a description of the error. For xTalk's own errors, each line of it is a set of numbers: the first item of the first line is the error's code, the second the line it happened on.

Errors inside functions

A try often goes inside a small function that gives back something sensible whatever happens:

ExampleRun it in the playground
function safeDivide pA, pB
   try
      return pA / pB
   catch tError
      return "n/a"
   end try
end safeDivide

put safeDivide(10, 4)
put safeDivide(1, 0)
put safeDivide("lots", 2)
Output
2.5
n/a
n/a

Raising your own: throw

throw raises an error of your own, with any text you like. It travels up through the handlers that called it, just like one of xTalk's, until a try catches it, and then the text arrives in the catch variable exactly as thrown:

ExampleRun it in the playground
command checkAge pAge
   if pAge is not a number then throw "Age must be a number"
   if pAge < 0 then throw "Age cannot be negative"
   put "Age" && pAge && "is fine"
end checkAge

try
   checkAge 30
   checkAge -2
   checkAge 50
catch tProblem
   put "Problem:" && tProblem
end try
Output
Age 30 is fine
Problem: Age cannot be negative

The third check never ran: the error jumped straight to catch. An error can travel a long way up:

ExampleRun it in the playground
command loadSettings
   readTheFile
end loadSettings

command readTheFile
   throw "the settings file is damaged"
end readTheFile

try
   loadSettings
catch tProblem
   put "Could not start:" && tProblem
end try
Output
Could not start: the settings file is damaged

Tidying up: finally

Lines after finally run whether or not there was an error: the place to close a file, unlock the screen, or put the cursor back.

ExampleRun it in the playground
try
   put "working"
   throw "a problem"
catch tError
   put "caught" && tError
finally
   put "tidied up"
end try
Output
working
caught a problem
tidied up

Errors that do not throw

Not every problem raises an error. Commands that deal with the world outside, files, the internet, other programs, often report a problem by setting the result (Your own commands) and carrying on. A try would not notice; you must look:

ExampleRun it in the playground
put URL "file:/no/such/folder/notes.txt" into tText
put the result
put "[" & tText & "]"
open file "/no/such/folder/notes.txt" for read
put the result
Output
can't open file
[]
can't open that file

So after any command that reaches outside your program, check the result on the very next line, before another command replaces it.

Try it yourself

Write a function toNumber that gives back its parameter if it is a number, and throws not a number: followed by the parameter if not. Then add up the list 4,x,10,oops,6 with it, skipping anything that is not a number and putting a warning for each.

Show a solution
ExampleRun it in the playground
function toNumber pValue
   if pValue is not a number then throw "not a number:" && pValue
   return pValue
end toNumber

put 0 into tTotal
repeat for each item tItem in "4,x,10,oops,6"
   try
      add toNumber(tItem) to tTotal
   catch tProblem
      put "Skipped," && tProblem
   end try
end repeat
put "Total:" && tTotal
Output
Skipped, not a number: x
Skipped, not a number: oops
Total: 20

Words in this lesson

Each one finds every lesson that uses it. The Dictionary has the whole story of each, with its syntax and more examples.