term_t
:
a reference to a Prolog term
The principal data type is term_t
. Type term_t
is what Quintus calls QP_term_ref
. This name indicates
better what the type represents: it is a handle for a term
rather than the term itself. Terms can only be represented and
manipulated using this type, as this is the only safe way to ensure the
Prolog kernel is aware of all terms referenced by foreign code and thus
allows the kernel to perform garbage collection and/or stack-shifts
while foreign code is active, for example during a callback from C.
A term reference is a C unsigned long, representing the offset of a variable on the Prolog environment stack. A foreign function is passed term references for the predicate arguments, one for each argument. If references for intermediate results are needed, such references may be created using PL_new_term_ref() or PL_new_term_refs(). These references normally live till the foreign function returns control back to Prolog. Their scope can be explicitly limited using PL_open_foreign_frame() and PL_close_foreign_frame()/PL_discard_foreign_frame().
A term_t
always refers to a valid Prolog term (variable,
atom, integer, float or compound term). A term lives either until
backtracking takes us back to a point before the term was created, the
garbage collector has collected the term, or the term was created after
a
PL_open_foreign_frame()
and PL_discard_foreign_frame()
has been called.
The foreign interface functions can either read, unify
or
write to term references. In this document we use the following
notation for arguments of type term_t
:
term_t +t
Accessed in read-mode. The `+' indicates the argument is `input'. term_t -t
Accessed in write-mode. term_t ?t
Accessed in unify-mode.
WARNING Term references that are accessed in `write' (-) mode will refer to an invalid term if the term is allocated on the global stack and backtracking takes us back to a point before the term was written.177This could have been avoided by trailing term references when data is written to them. This seriously hurds performance in some scenarios though. If this is desired, use PL_put_variable() followed by one of the PL_unify_*() functions. Compounds, large integers, floats and strings are all allocated on the global stack. Below is a typical scenario where this may happen. The first solution writes a term extracted from the solution into a. After the system backtracks due to PL_next_solution(), a becomes a reference to a term that no longer exists.
term_t a = PL_new_term_ref(); ... query = PL_open_query(...); while(PL_next_solution(query)) { PL_get_arg(i, ..., a); } PL_close_query(query);
There are two solutions to this problem. One is to scope the term reference using PL_open_foreign_frame() and PL_close_foreign_frame() and makes sure it goes out of scope before backtracking happens. The other is to clear the term reference using PL_put_variable() before backtracking.
Term references are obtained in any of the following ways:
Term references can safely be copied to other C variables of type
term_t
, but all copies will always refer to the same term.
pl_mypredicate(term_t a0, term_t a1) { term_t t0 = PL_new_term_refs(2); term_t t1 = t0+1; ... }
Note that returning from the foreign context to Prolog will reclaim all references used in the foreign context. This call is only necessary if references are created inside a loop that never exits back to Prolog. See also PL_open_foreign_frame(), PL_close_foreign_frame() and PL_discard_foreign_frame().
Prolog implements two mechanisms for avoiding stack overflow: garbage
collection and stack expansion. On machines that allow for it, Prolog
will use virtual memory management to detect stack overflow and expand
the runtime stacks. On other machines Prolog will reallocate the stacks
and update all pointers to them. To do so, Prolog needs to know which
data is referenced by C code. As all Prolog data known by C is
referenced through term references (term_t
), Prolog has all
the information necessary to perform its memory management without
special precautions from the C programmer.
Atoms are the central representation for textual constants in Prolog. The transformation of a character string C to an atom implies a hash-table lookup. If the same atom is needed often, it is advised to store its reference in a global variable to avoid repeated lookup.
int64_t
is defined in the stdint.h
standard
header and provides platform-independent 64-bit integers. Portable code
accessing Prolog should use this type to exchange integer values. Please
note that
PL_get_long()
can return FALSE
on Prolog integers that cannot be
represented as a C long. Robust code should not assume any of the
integer fetching functions to succeed, even if the Prolog term
is known to be an integer.
As of SWI-Prolog 7.3.12, the arity of terms has changed from int
to size_t
. To deal with this transition, all affecting
functions have two versions, where the old name exchanges the arity as int
and a new function with name *_sz() exchanges the arity as
size_t
. If the C macro PL_ARITY_AS_SIZE is defined before
loading SWI-Prolog.h
, macros are put in place that map the
old names to the new functions. Without precautions, the old code is
compatible, but the following warning is printed when compiling:
#warning "Term arity has changed from int to size_t." #warning "Please update your code and use #define PL_ARITY_AS_SIZE 1."
To make the code compile silently again, include SWI-Prolog.h
as below and change the types you use to represent arity from int
to size_t
. Please be aware that size_t
is
unsigned.
#define PL_ARITY_AS_SIZE #include <SWI-Prolog.h>