Version 1 is in SWI-cpp.h
; version 2 is in SWI-cpp2.h
,
SWI-cpp2.cpp
, SWI-cpp2-plx.h
, and SWI-cpp2-atommap.h
.
The overall structure of the API has been retained - that is, it is a
thin layer of lightweight classes on top of the interface provided by
SWI-Prolog.h
. Based on experience with the API, most of the
conversion operators and some of the comparison operators have been
removed or deprecated, and replaced by “getter” methods; the
overloaded constructors have been replaced by subclasses for the various
types. Some changes were also made to ensure that the
operator for []
PlTerm
and PlTermv
doesn't cause unexpected implicit conversions.1If
there is an implicit conversion operator from PlTerm
to term_t
and also to char*
, then the
operator is ambiguous if []
f
is overloaded to accept a term_t
or char*
in the code PlTerm t=...; f(t[0])
.
Prolog errors are now converted to C++ exceptions (which contain the
exception term rather being a subclass of PlTerm
as in
version 1), where they can be caught and thrown using the usual C++
mechanisms; and the subclasses that create exceptions have been changed
to functions. In addition, an exception type PlFail
has
been added, together with PlCheckFail
, to allow more
compact code by “short circuit” return to Prolog on failure.
A convenience class for creating blobs has been added, so that an existing structure can be converted to a blob with only a few lines of code. More specifically:
SWI-cpp2.cpp
has been added, containing the
implementation of some functions. This is included by default from SWI-cpp2.h
or can be compiled separately.SWI-Prolog.h
, and have the same names with the “PL” replaced
by “Plx” .2 “Pl” is
used throughout the SWI-cpp2.h
interface, and the “x” is
for “eXtended with eXception handling.’ Where
appropriate, these check return codes and throw a C++ exception (created
from the Prolog error). See section
1.6.4. Many of these wrapper functions are also methods in the PlAtom
and PlTerm
classes, with the arguments changed from
atom_t
and term_t
to PlAtom
and PlTerm
and in some cases char*
and wchar_t*
changed
to std::string
and std::wstring
. These
wrappers are available if you include SWI-cpp2.h
(they are
in a separate SWI-cpp2-plx.h
file for ease of maintenance).false
from a foreign predicate to
indicate failure, you can throw PlFail(). The convenience
function PlCheckFail(rc) can
be used to throw PlFail() if false
is returned from
a function in
SWI-Prolog.h
. If the wrapper functions or class methods are
used, Prolog errors result in a C++ PlException
exception.3If
a “Plx_” wrapper is used to call a SWI-Prolog.h
function, a Prolog error will have already resulted in throwing PlException
;
PlCheckFail(rc) is used to
additionally throw
PlFail
, similar to returning false
from the
top-level of a foreign predicate - Prolog will check for an error and
call throw/1 if
appropriate.PlException
class is now a subclass of std::exception
and encapsulates a Prolog error. Prolog errors are converted into throw PlException(...)
.
If the user code does not catch the PlException
, the PREDICATE()
macro converts the error to a Prolog error upon return to the Prolog
caller.(char*)t
, (int64_t)t
,
static_cast<char*>(t)
) have been deprecated, replaced
by “getters” (e.g.,
t.as_string()
, t.as_int64_t()
).std::string
, comparison operators. The PlTerm::as_string()
method allows specifying the encoding to use whereas the ==
and similar operators do not allow for this.char*
have been replaced by methods
that return std::string
to ensure that lifetime issues
don't cause subtle bugs.4If you
want to return a char*
from a function, you should not do return
t.as_string().c_str()
because that will return a pointer to local or stack memory. Instead,
you should change your interface to return a std::string
and apply the c_str()
method to it. These lifetime
errors can sometimes be caught by specifying the Gnu C++ or
Clang options -Wreturn-stack-address
or -Wreturn-local-addr
- as of 2023-04, Clang seems to do a better analysis.char*
or wchar_t*
arguments also accept std::string
or std::wstring
arguments. Where possible, encoding
information can also be specified.PlString
has been renamed to PlTerm_string
to make it clear that it's a term that contains a Prolog string.PL_...(term_t, ...)
methods have been added to PlTerm
,
and PL_...(atom_t, ...)
methods have been added to PlAtom
.
Where appropriate, the arguments use PlTerm
, PlAtom
,
etc. instead of term_t
, atom_t
, etc.int
for
true/false now return a C++ bool
.term_t
, atom_t
,
etc.) have been renamed from handle
, ref
, etc.
to
C_
.5This is done by
subclassing from Wrapped<term_t>
, Wrapped<atom_t>
,
etc., which define the field C_
, standard constructors, the
methods is_null(), not_null(), reset(),
reset(v), reset_wrapped(v), plus the constant null
.
This value can be accessed by the unwrap() and unwrap_as_ptr()
methods. There is also a “friend” function PlUnwrapAsPtr().PlControl::context_unique_ptr<ContextType>()
has been added, to simplify dynamic memory allocation in
non-deterministic predicates.PlStringBuffers
provides a simpler interface for
allocating strings on the stack than PL_STRINGS_MARK() and PL_STRINGS_RELEASE().
However, this is mostly not needed because most functions now use std::string
:
see section 1.6.9.1.PlStream
provides a simpler interface for streams than
PL_get_stream(), PL_acquire_stream(), and PL_release_stream().
See section 1.6.9.2.record_t
have been added. The
PlRecordExternalCopy
class contains the opaque handle, as a
convenience.control_t
has been added and the
PREDICATE_NONDET() has
been modified to use it.More details on the rationale and how to port from version 1 to version 1 are given in section 1.8 and section 1.9.