Tutorial: Handling Errors

How to deal with the inevitable.

Error Handling

In Quorum, we may occasionally encounter an error. Errors in computer programs we write can be caused by a wide variety of problems, from incorrect user input to bugs in our programs. For example, if a user attempts to divide a number by zero, Quorum will alert us to a DivideByZeroError. We can reproduce this error in Quorum with the following code:

number result = 12/0
output result

When this error is encountered Quorum will stop running and the user will be provided an error message, indicating that a divide by zero error has occurred. Sometimes we may want Quorum to do something more intelligent when an error is encountered. This is what error handling will allow us to do. In the sections to follow you will learn how to handle errors that might happen and how to create our own custom errors. Because error handling in Quorum online is slightly different than offline, development environments will not be provided for this tutorial. We encourage trying this tutorial in offline mode.

The Error class

The error class is a class in the Quorum standard library that represents a general error in Quorum(Quorum.Language.Errors.Error). This error stores an error message, a general message telling the user something about the error, and a stack trace, the state of the call stack when the error occurred.

All errors in Quorum inherit from the Error class (this is important when we create our own custom error). Some of these errors include, CastError, IndexOutOfBoundsError, and DivideByZeroError.

Detecting an Error

Sometimes we might want to handle an error that has occurred. For example, using the divide by zero example, suppose our code asked the user to enter a divisor. If the user entered 0 your program would stop running and display an error message(see the following code example).

text userInput = input("divide by?")
integer divisor = cast(integer, userInput)
result = 12/divisor
output result

Instead of causing the program to fail, we could detect the error, let the user know about the problem, and set the divisor to 1. We can do this using the check/detect statement. In the check block you place the code that may cause the error.

integer result = 0
check
    text userInput = input("divide by?")
    integer divisor = cast(integer, userInput)
    result = 12/divisor
end
output result

Then we can use the detect block to specify what type of error to handle or detect. The detect follows the format detect <name> is <error type> It first specifies the name of the error variable (this can be a name of your choosing, but we use "e"). Then you can specify the type of error you will detect. In this case we want the DivideByZeroError.

detect e is DivideByZeroError
    //give the user the error and set the divisor to 1
    say e:GetErrorMessage()
    result = 12/1
end
output result

In addition to the check and detect blocks, we can specify an optional always block. In the always block you can specify code that needed to execute no matter what the outcome of the check block (it will execute if an error occurred or no error occurred).

always
    output "calculating result"
end

Putting it all together: the following code will ask the user for a number and check it for the specified error. In this detect block we will detect more than one type of error, a general Error and a DivideByZeroError, because the user could input text which would also be invalid (e.g. "zero"). Once the check and detect blocks are executed the always will be called and a result will be given.

use Libraries.Language.Errors.Error
use Libraries.Language.Errors.DivideByZeroError

class Main
    action Main
        number result = 0
        check
            text userInput = input("divide by?")
            integer divisor = cast(integer, userInput)
            result = 12/divisor
        detect e is Error or DivideByZeroError
            output e:GetErrorMessage()
            result = 12/1
        always
            output "calculating result"
        end
        output "The result is " + result
    end
end

Alerts

Sometimes we may need to trigger an error manually. This can be done using alerts which follow two formats, alert(<text>) and alert(<error>). In the first format an error of type Error is generated with the message specified by <text>.

alert("Zero is not a valid input")

In the last format the full error is passed. The following is an example:

DivideByZeroError error
error:SetErrorMessage("Zero is not a valid input")
alert(error)

Custom Errors

Creating your own custom errors in Quorum is requires that we extend the Libraries.Language.Errors.Error class.

use Libraries.Language.Errors.Error
class MyError is Error
end

It is also important to note that the error handling system does not support inheritance hierarchies, like most of Quorum. In other words, errors can inherit from only one other class: Error. When using the detect statement, we can either detect all types of errors with Error or a list of specific errors you wish to detect.

Next Tutorial

In the next tutorial, we will discuss Writing Quorum Plugins, which describes How to connect to Java (or other languages) from Quorum.