Did you know ... | Search Documentation: |
![]() | The class PlFail (version 2) |
The PlFail
class is used for short-circuiting a function
when failure or an exception occurs and any errors will be handled in
the code generated by the PREDICATE() macro. See also
section 2.18.2).
For example, this code:
PREDICATE(unify_zero, 1) { if ( !PL_unify_integer(A1.C_, 0) ) return false; return true; }
can instead be written this way:
void PREDICATE(unify_zero, 1) { if ( !PL_unify_integer(A1.C_, 0) ) throw PlFail(); return true; }
or:
PREDICATE(unify_zero, 1) { PlCheck(PL_unify_integer(t.C_, 0)); return true; }
or:
PREDICATE(unify_zero, 1) { PlCheck(A1.unify_integer(0)); return true; }
or:
PREDICATE(unify_zero, 1) { return A1.unify_integer(0); }
Using throw PlFail()
in performance-critical code can
cause a signficant slowdown. A simple benchmark showed a 15x to 20x
slowdown using throw PlFail()
compared to return
false
(comparing the first code sample above with the second and
third samples; the speed difference seems to have been because in the
second sample, the compiler did a better job of inlining). However, for
most code, this difference will be barely noticeable.
There was no significant performance difference between the C++ version and this C version:
static foreign_t unify_zero(term_t a1) { return PL_unify_integer(a1, 0); }
In general, wherever there is a method that wraps a C "PL_" function, PlCheck() can be used to return failure to Prolog from the "PL_" function.
The code for PlCheck() is very simple - it checks the return
code and throws PlFail
if the return code isn't "true". If
the return code is from a Prolog function (that is, a function starting
with "PL_"), the return code can be "false" either because of failure or
because an exception happened. If the cause is an exception, then the
only sensible thing is to return to Prolog immediately; throwing PlFail
will do this. See also section 2.18.2.