.. _throwing-handling-errors: **************************** 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 "|dot| 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. :: { handle_error => { #time_of_day = time_of_day(0) } #time_of_day = time_of_day(math_random(0, 25)) } ?> [#time_of_day->greeting] I am an HTML document. 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. .. seealso:: For detailed documentation on creating and handling errors in Lasso, see the :ref:`error-handling` chapter.