Are the values returned from a foreign function, and also the values returned from the various int PL_...() functions always 0 or 1 (FALSE or TRUE)?
(A few functions return something different, such as PL_new_atom(), but they’re defined as returning something different from int, such as atom_t or term_t.)
foreign_t
pl_lowercase(term_t u, term_t l)
{ ...
int rval;
...
rval = PL_unify_atom_chars(l, copy);
...
return rval;
}
foreign_t is a typedef for long unsigned int, so we have (on my machine) a signed 32-bit value being put into an unsigned 64-bit value; and implicit conversions between signed and unsigned in C can be error-prone. However, if rval is always 0 or 1 (FALSE or TRUE), it should be harmless.
Even so, it seems that things would be safer if all the boolean (int) return values were the same, e.g. declare foreign_t rval corresponding to a revised definition foreign_t PL_unify_atom_chars(term_t t, const char *chars).
PS: Some of the PL_put_…() functions, such as PL_put_variable() are documented as not returning anything (return type void) but SWI-Prolog.h has them as return type int. Presumably, this is a documentation typo.
Almost all the API functions are indeed defined as int and always return TRUE or FALSE (1 or 0). foreign_t is uintptr_t, and comes in two flavors. For any predicate it may return TRUE or FALSE. Non-det predicates may return using PL_retry() or PL_retry_address() which pack a small integer or word-aligned address that can be used by the foreign predicate to keep track of the state for backtracking.
There is AFAIK nothing really wrong. I do not see much reason to change the return type of the API functions to foreign_t. It probably mostly results in a lot of compiler warnings for code doing int rc = PL_....().
That is indeed a problem with the docs. Please correct if you find one (just fixed PL_put_variable(), PL_put_bool() and PL_put_atom()). Over the years I’ve moved to a programming style where I put a lot of the API function calls in a large conjunction, so we get code as below. Some of the API functions can technically not fail and used to have a void return type. Void functions are a bit unpractical using this style of programming though. Note that almost all API functions allocate something (often on the Prolog stacks) and can thus result in a resource exception or have other error conditions.
This is a very useful style, I have seen it in JavaScript as well. How do you deal with the side effects though? (Like the allocations you mention yourself)
All (almost) the PL_*() functions create side effects that are subject to backtracking and/or garbage collection Typically there is no need to deal with side effects except for non-Prolog side effects created by the foreign predicate.