Skip to content

Exception handling in Toit#

Try and finally#

The try block in Toit is used to execute code following the try statement as a “normal” part of the program.

The finally keyword defines a block of code to run when the try block is final. The finally block will be executed no matter if the try block raises an error or not. This can be useful to close objects and clean up resources.

main:
  connection ::= device.ConsoleConnection.open
  try:
    accelerometer := Accelerometer.start
    try:
      print "started"
      while true:
        force := movement accelerometer
        print "got movement: $force - moving: $(is_moving force)"
        sleep --ms=1000
    finally:
      accelerometer.close
  finally:
    connection.close

Throw#

The throw keyword in Toit is used to explicitly throw an exception from a method or any block of code. Any object can be thrown. Currently the core libraries often throw strings containing error messages. Although it looks like a keyword, throw is implemented as a function that takes a value to be thrown.

Catch#

Code that may throw an exception can be wrapped in a catch. This is implemented as a function that takes the possibly throwing code as a block. Catch will return the thrown object, or null if no object was thrown.

Catch takes two optional arguments

  • The --trace argument is a boolean or a block that evaluates to a boolean. It controls whether the caught exception is reported in the console. By default the exception is not reported. The trace block is passed an argument that is the thrown object.

  • The --unwind argument takes a boolean or a block that evaluates to a boolean. It determines whether the execution stack continues to unwind after the catch. By default unwind is false. If the block evaluates to true then the exception will continue to unwind the call stack as if the catch were not present. The unwind block is passed the thrown object as an argument, which it can use to determine whether to unwind.

my_function:
  my_exception := catch --trace:
    code_that_might_throw 42 103
  if my_exception:
    code_to_run_when_an_exception_was_thrown "foo" "bar"

// Identifies exceptions that we want to catch.  Every other
// exception will result in a stack trace on the console and
// an uncaught exception (which may nevertheless be caught
// further up the call stack).
is_bad thrown_object:
  return thrown_object != "HARMLESS_ERROR"

my_other_function:
  exception := catch
      --trace=: | thrown | is_bad thrown
      --unwind=: | thrown | is_bad thrown:
    code_that_might_throw 42 103
  if exception:
    // A harmless error was thrown.
    code_to_run_when_an_exception_was_thrown "foo" "bar"