For example, consider cases where we want to propagate errors only in
specific instances:
auto result = read_data(); // something like ErrorOr<ByteBuffer>
if (result.is_error() && result.error().code() != EINTR)
continue;
auto bytes = TRY(result);
The TRY invocation will currently copy the byte buffer when the
expression (in this case, just a local variable) is stored into
_temporary_result.
This patch binds the expression to a reference to prevent such copies.
In less trival invocations (such as TRY(some_function()), this will
incur only temporary lifetime extensions, i.e. no functional change.
If USING_AK_GLOBALLY is not defined, the name IsLvalueReference might
not be available in the global namespace. Follow the pattern established
in LibTest to fully qualify AK types in macros to avoid this problem.
I'm not sure there's a material improvement from this patch. However,
I've been reading the error handling code from multiple projects and
was excited to see Serenity being able to handle assignment
(`auto x = TRY(make_x())`) the same way as actions (`TRY(do_x())`).
I think it's worth documenting that this is only possible due to
non-standard extensions.
We now use AK::Error and AK::ErrorOr<T> in both kernel and userspace!
This was a slightly tedious refactoring that took a long time, so it's
not unlikely that some bugs crept in.
Nevertheless, it does pass basic functionality testing, and it's just
real nice to finally see the same pattern in all contexts. :^)
"result" is a tad bit too generic to provide a clash-free experience -
we found instances in LibJS where this breaks already. Essentially this
doesn't work:
auto foo = TRY(bar(result));
Because it expands to the following within the TRY() scope:
{
auto result = bar(result);
...
}
And that of course fails:
error: use of ‘result’ before deduction of ‘auto’
The simple solution here is to use a name that is much less likely to
clash with anything used in the expression ("_temporary_result"). :^)
The way we use classes like Kernel::KResultOr<T> and AK::Result<T, E>
makes checking for errors (and short-circuiting returns) quite verbose.
This patch adds a new TRY(expression) macro that either evaluates to
the released result of the expression if successful, or returns the
error if not.
Before:
auto foo_or_error = get_foo();
if (foo_or_error.is_error())
return foo_or_error.release_error();
auto foo = foo_or_error.release_value();
After:
auto foo = TRY(get_foo());
The macro uses a GNU C++ extension which is supported by GCC, Clang,
Intel C++, and possibly others. It's not *ideal*, but since it makes our
codebase considerably nicer, let's try(!) it out. :^)
Co-authored-by: Ali Mohammad Pur <mpfard@serenityos.org>