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.20.2).
For example, this code, using the C API:
PREDICATE(unify_zero, 1) { if ( !PL_unify_integer(A1.unwrap(), 0) ) return false; // could be an error or failure Sprintf("It's zero!\n"); return true; }
can instead be written this way, using the C++ API:
PREDICATE(unify_zero, 1) { PlCheckFail(A1.unify_integer(0)); Sprintf("It's zero!\n"); return true; }
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. And if the code
usually succeeds, there is no significant difference.
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); }
If one of the C "PL_" functions in SWI-Prolog.h
returns
failure, this can be either a Prolog-style failure (e.g. from
PL_unify() or PL_next_solution()) or an error. If the
failure is due to an error, it's usually best to immediately return to
Prolog - and this can be done with the PlCheckEx() function, which turns
a Prolog error into a C++ PlException
. PlCheckFail() calls
PlCheckEx() and additionally throws PlFail() if the failure is for
Prolog failure.
PlCheckEx() calls PL_exception() to see if there is a Prolog
exception; if so, the Prolog exception is converted to a
PlException
object, which is then thrown. For more details
on the C++ exceptions, see section 2.18.