require and error handling
The require function allows you to verify Boolean conditions, check for null values, or ensure non-empty collections.
For details, see require and
require_not_empty in the
API reference.
The functions that raise and catch these exceptions are documented together on this page: require and
require_not_empty raise them, rell.error
raises one unconditionally, and try_call and try_call_catch catch them.
Variants
Checking Boolean conditions
require(boolean, text): Throws an exception if the boolean argument isfalse, using the provided text as the error message.
Checking for null values
require(T?, text): T- gives an exception if the argument isnull; otherwise returns the argument.require_not_empty(T?, text): T- same as the previous one.
Checking for empty collections
require_not_empty(list<T>, text): list<T>- gives an exception if the argument is an empty list; otherwise it returns the list.require_not_empty(set<T>, text): set<T>- gives an exception if the argument is an empty set; otherwise it returns the set.require_not_empty(map<K,V>, text): map<K,V>- gives an exception if the argument is an empty map; otherwise, it returns the map.
Nullable collections
- When passing a nullable collection to
require_not_empty, it throws an exception if it is eithernullor empty.
Example
function calculate(): integer? = 123;
function get_list(): list<integer> = [1, 2, 3];
function try_to_get_list(): list<integer>? = [4, 5];
val x: integer? = calculate();
val y = require(x, "x is null"); // type of "y" is "integer", not "integer?"
print(y); // 123
val p: list<integer> = get_list();
require_not_empty(p, "List is empty");
val q: list<integer>? = try_to_get_list();
require(q); // fails if q is null
require_not_empty(q); // fails if q is null or an empty list
Error handling with try_call and try_call_catch
The try_call function catches
exceptions and optionally provides fallback values:
val s = "xyz";
val int_or_null = try_call(integer.from_hex(s, *)); // Returns null on failure
val int_or_default = try_call(integer.from_hex(s, *), -1); // Returns -1 on failure
print(int_or_null, int_or_default); // null -1
The try_call_catch function
(since 0.14.16) catches only require exceptions and returns a
try_call_result<T>
that allows inspecting the error message:
function may_fail(): integer {
require(false, "This fails");
return 0;
}
val result = try_call_catch(may_fail(*)); // Returns try_call_result with error info
print(result); // try_call_result{error=This fails}
Both functions restore database state on failure – any writes are rolled back. try_call catches all exceptions, while
try_call_catch only catches require exceptions and re-throws others.
rell.error
The rell.error() function (since 0.14.15) fails unconditionally, raising an exception with an optional message:
rell.error(); // Throws an exception with a null message
rell.error('Not allowed.'); // Throws an exception with the message 'Not allowed.'
Unlike require(false, message), rell.error() signals the end of control flow to the compiler, in the same way a
return statement does. This lets the compiler narrow types after the call:
function f(x: integer?): integer {
if (x == null) {
rell.error('null argument');
}
return x * x; // The compiler knows that x cannot be null here
}
print(f(5)); // 25