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.19.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(PL_unify_integer(t.C_, 0));
return true;
}
or:
PREDICATE(unify_zero, 1)
{ PlCheckFail(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);
}
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. PlCheck()
calls PlCheckEx() and additionally throws PlFail() if the failure is for
Prolog failure.
The code for PlCheck() is just
void PlCheck(int rc)
{ if ( !PlCheckEx(rc) ) throw PlFail(); }
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.17.