12 Foreign Language Interface
AllApplicationManualNameSummaryHelp

  • Documentation
    • Reference manual
      • Foreign Language Interface
        • Overview of the Interface
        • Linking Foreign Modules
        • Interface Data Types
          • Type term_t: a reference to a Prolog term
          • Other foreign interface types
        • The Foreign Include File
        • Linking embedded applications using swipl-ld
        • The Prolog `home' directory
        • Example of Using the Foreign Interface
        • Notes on Using Foreign Code
    • Packages

12.3 Interface Data Types

12.3.1 Type 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 +tAccessed in read-mode. The `+' indicates the argument is `input'.
term_t -tAccessed in write-mode.
term_t ?tAccessed 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:

  • Passed as argument
    The C functions implementing foreign predicates are passed their arguments as term references. These references may be read or unified. Writing to these variables causes undefined behaviour.
  • Created by PL_new_term_ref()
    A term created by PL_new_term_ref() is normally used to build temporary terms or to be written by one of the interface functions. For example, PL_get_arg() writes a reference to the term argument in its last argument.
  • Created by PL_new_term_refs(int n)
    This function returns a set of term references with the same characteristics as PL_new_term_ref(). See PL_open_query().
  • Created by PL_copy_term_ref(term_t t)
    Creates a new term reference to the same term as the argument. The term may be written to. See figure 7.

Term references can safely be copied to other C variables of type term_t, but all copies will always refer to the same term.

term_t PL_new_term_ref()
Return a fresh reference to a term. The reference is allocated on the local stack. Allocating a term reference may trigger a stack-shift on machines that cannot use sparse memory management for allocation of the Prolog stacks. The returned reference describes a variable.
term_t PL_new_term_refs(int n)
Return n new term references. The first term reference is returned. The others are t+1, t+2, etc. There are two reasons for using this function. PL_open_query() expects the arguments as a set of consecutive term references, and very time-critical code requiring a number of term references can be written as:
pl_mypredicate(term_t a0, term_t a1)
{ term_t t0 = PL_new_term_refs(2);
  term_t t1 = t0+1;

  ...
}
term_t PL_copy_term_ref(term_t from)
Create a new term reference and make it point initially to the same term as from. This function is commonly used to copy a predicate argument to a term reference that may be written.
void PL_reset_term_refs(term_t after)
Destroy all term references that have been created after after, including after itself. Any reference to the invalidated term references after this call results in undefined behaviour.

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().

12.3.1.1 Interaction with the garbage collector and stack-shifter

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.

12.3.2 Other foreign interface types

atom_t
An atom in Prolog's internal representation. Atoms are pointers to an opaque structure. They are a unique representation for represented text, which implies that atom A represents the same text as atom B if and only if A and B are the same pointer.

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.

functor_t
A functor is the internal representation of a name/arity pair. They are used to find the name and arity of a compound term as well as to construct new compound terms. Like atoms they live for the whole Prolog session and are unique.
predicate_t
Handle to a Prolog predicate. Predicate handles live forever (although they can lose their definition).
qid_t
Query identifier. Used by PL_open_query(), PL_next_solution() and PL_close_query() to handle backtracking from C.
fid_t
Frame identifier. Used by PL_open_foreign_frame() and PL_close_foreign_frame().
module_t
A module is a unique handle to a Prolog module. Modules are used only to call predicates in a specific module.
foreign_t
Return type for a C function implementing a Prolog predicate.
control_t
Passed as additional argument to non-deterministic foreign functions. See PL_retry*() and PL_foreign_context*().
install_t
Type for the install() and uninstall() functions of shared or dynamic link libraries. See section 12.2.3.
int64_t
Actually part of the C99 standard rather than Prolog. As of version 5.5.6, Prolog integers are 64-bit on all hardware. The C99 type 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.

12.3.2.1 PL_ARITY_AS_SIZE

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>