Skip to content

Exceptions

Gambol implements zero cost exceptions that also provide a trace stack at runtime. The exceptions are zero cost in the sense that as long as the program does not deviate from the normal path of execution they will not have have an impact on the performance of the application. In practice though zero cost exceptions could have an impact on the compiler preventing the viability of certain optimizations such as tail calls. In those extreme cases (usually involving numerical calculations) it is possible to turn off exceptions to give the compiler more freedom to run additional optimizations using attributes on functions.

Exception class

Exceptions are types that are derived from the Exception class. All exceptions have to be nominally derived from Exception. Here is the interface for the base Exception class:

type ExceptionTrace {

  #default 
  = (s Self, o Self)

  function_ast Pointer
  function_symbol String
  file_name String
  line Int64 
  column Int64

}

type Exception inherits Stringable {

  message String
  trace_stack List[ExceptionTrace]()

  fun str(s Self) -> String

}

Try catch

To raise exceptions create an instance of your exception and use the raise keyword followed by the exception object. To catch exceptions the code must be wrapped in a try block followed by a number of catch blocks each taking a parameter of an exception type. To create a wildcard catch block, simply catch a parameter of the base exception type Exception.

type MyException inherits Exception {}

fun test_exceptions_inner() {

  val = Int.parse(input(`enter a number between 1-3: `))

  if val == 1 then raise MyException() { message: `val was one` } end

  if val == 2 then raise IndexOutOfRangeException() end

  if val == 3 then raise NotImplementedException() end
}

fun test_exceptions() {

  test_exceptions_inner()
}

fun test_exceptions_outer() {

  test_exceptions()
}

try

  test_exceptions_outer()

catch me MyException then

  print(`caught exception ` me)

catch e Exception then

  print(`catch all block ` e)
end

output

enter a number between 1-3: 1
caught exception global.<a>.MyException: val was one
        /path_to/test/a.gambol line 27 col 1
        /path_to/test/a.gambol  test_exceptions_outer line 22 col 0
        /path_to/test/a.gambol  test_exceptions line 17 col 0
        /path_to/test/a.gambol  test_exceptions_inner line 8 col 25

Catch block parameters are all implicitly nillable and nominal. Neither the try block nor the catch block introduce any scope and all catch formals are available outside of the try-catch block. This means you could potentially check a catch parameter to see if an exception is caught or not after the fact. You could define a scope however in each block if you like to.

At the highest level each Gambol module wraps the entire code in a try-catch block so that if any exception is thrown it will be displayed to the user before terminating the program.