TRUE
on success. PL_unify()
does not evaluate attributed variables (see section
8.1), it merely schedules the goals associated with the attributes
to be executed after the foreign predicate succeeds.219Goal
associated with attributes may be non-deterministic, which we cannot
handle from a callback. A callback could also result in deeply nested
mutual recursion between C and Prolog and eventually trigger a C stack
overflow.
Care is needed if PL_unify()
returns FALSE
and the foreign function does not immediately
return to Prolog with
FALSE
. Unification may perform multiple changes to either
t1 or t2. A failing unification may have created
bindings before failure is detected. Already created bindings are
not undone. For example, calling PL_unify()
on a(X, a)
and
a(c,b)
binds X to c
and fails when
trying to unify
a
to b
. If control remains in C or even if we
want to return success to Prolog, we must undo such bindings.
In addition, PL_unify()
may have failed on an exception, typically a resource (stack)
overflow. This can be tested using PL_exception(),
passing 0 (zero) for the query-id argument. Foreign functions that
encounter an exception must return FALSE
to Prolog as soon
as possible or call PL_clear_exception()
if they wish to ignore the exception. Note that there can only be an
exception if PL_unify()
returned FALSE
. This is achieved using PL_open_foreign_frame()
and PL_rewind_foreign_frame(),
as shown in the snippet below.
{ fid_t fid = PL_open_foreign_frame(); ... if ( !PL_unify(t1, t2) ) { if ( PL_exception(0) ) { PL_close_foreign_frame(fid); return FALSE; } PL_rewind_foreign_frame(fid); } ... PL_close_foreign_frame(fid); }
This code is only needed if the foreign predicate does not return
immediately to Prolog when PL_unify()
fails - there is an implicit frame around the entire predicate, and
returning FALSE
undoes all bindings when that frame is
closed.