Throwing and Handling Errors¶
When Lasso code encounters a problem, it throws an error. Part of learning to code well is knowing when your code should explicitly throw an error, and learning how to gracefully handle an error that has been thrown.
Let’s continue with our ongoing code example. Currently we accept any integer
value for the hour. It could be -5 or 42. Since a 24-hour clock runs from 0–23,
we should probably make sure that our time_of_day
type only accepts those
values.
Throwing an Invalid Value Error¶
The code below updates our time_of_day
custom type to ensure that it is
always passed a valid hour. Before these changes, the following code samples
would both “work”:
// Creator method with invalid data
time_of_day(77)
// Setter method for "hour" data member
time_of_day->hour(89)
With the updated code below, both of these examples will now fail, throwing an error about invalid values.
define time_of_day => type {
data public hour::integer
data private time_info = map(
`morning` = map('greeting'="Good Morning!", 'bgcolor'='lightyellow'),
`afternoon` = map('greeting'="Good Afternoon!", 'bgcolor'='lightblue'),
`evening` = map('greeting'="Good Evening!", 'bgcolor'='lightgray')
)
public onCreate(datetime::date=date) => .onCreate(datetime->hour)
public onCreate(hour::integer) => {
.hour = #hour
}
public hour=(rhs::integer) => {
if(#rhs < 0 or #rhs > 23) => {
fail(
error_code_invalidParameter,
error_msg_invalidParameter + ': hour must be between 0 and 23'
)
}
.'hour' = #rhs
return #rhs
}
public greeting => {
return .'time_info'->find(.asString)->find('greeting')
}
public bgColor => .'time_info'->find(.asString)->find('bgcolor')
public asString => {
if(.hour >= 5 and .hour < 12) => {
return 'morning'
else(.hour >= 12 && .hour < 17)
return 'afternoon'
else
return 'evening'
}
}
}
This new type definition has two changes.
The biggest is the addition of the time_of_day->hour=
method. The code
starts with public hour=(rhs::integer) => {
. This method overrides the
current public setter method for the hour data member. All setter methods end
with an equal sign in their name and take at least one parameter which is the
new value to use. This is the method that would get called with the following
code:
local(example) = time_of_day
#example->hour = 9 // Calling the setter method
In this example, “9” would be the value in the “rhs” local variable sent to the
setter. This new setter method first checks that the value is between 0 and 23
before proceeding. If the value is not between that time, it calls fail
with
an error code and an error message. The code can be any integer value. We are
using error_code_invalidParameter
which is a method that returns the integer
value that Lasso has set as the standard for use when a bad value in a parameter
is encountered. The error message can be any string, and we’re using
error_msg_invalidParameter
to get the standard error message for a bad value
in a parameter and then concatenate on a message that’s a little more specific
to help programmers fix their code.
The other change we made is harder to notice. In the onCreate(hour::integer)
method, we changed the code from .'hour' = #hour
to .hour = #hour
. This
small change (removing the quotes around “.hour”) has the code use the new
public setter method instead of setting the data member directly. (The new
setter method must still set the data member directly. If it didn’t, we would be
stuck in an infinite loop as it kept calling itself.)
Basic Error Handling¶
Occasionally, there are times when we know that code we write could fail, and we
want to gracefully handle the error. In these cases, we wrap the code that could
fail in a protect
block and use either handle
or handle_error
to
deal with any cleanup.
We’re going to update our page code with a bit of a contrived example. In the
new code, I’m going to create a time_of_day
object based on a random number
between 0 and 25. This will fail for 24 and 25, so I’m going to wrap the code in
a protect
block and have it default to midnight (0) if there are any errors.
<?lasso
local(time_of_day)
protect => {
handle_error => {
#time_of_day = time_of_day(0)
}
#time_of_day = time_of_day(math_random(0, 25))
}
?>
<html>
<body style="background-color: [#time_of_day->bgcolor]">
[#time_of_day->greeting] I am an HTML document.
</body>
</html>
The code that’s wrapped inside the protect
block is not only the code that
may fail, but also the code that runs if there’s an error (the handle_error
block). It’s important that any handle_error
or handle
code be written
above the code that may fail, otherwise those handlers will not be registered to
be called when a problem occurs.
See also
For detailed documentation on creating and handling errors in Lasso, see the Error Handling chapter.