Low-Level Interface
Author: Fred Dushin
Keywords: JPL,java,prolog

up prev next API

JPL 2.0.2 Low-Level Interface

### Table of Contents

- Introduction
- Supported Data Types
- jpl.fli.Prolog
- Using the Low-Level Interface
- Caveats

- Sequential Term References
- Variable-length Argument Lists
- Currently unsupported FLI functions
- Unsupportable FLI functions

### Introduction

[Note: if you just want to build hybrid Java+Prolog applications, you probably don't need to know about this interface: see the High-Level interface documentation]
The JPL Low-Level interface is implemented by the Java package jpl.fli. This package contains a set of classes that mirror the data types in the SWI-Prolog Foreign Language Interface (FLI), together with a class jpl.fli.Prolog, which contains static variables and static native methods which reflect the constants and functions in the FLI. The package is designed to serve as a direct translation of the Prolog FLI and is generally not intended for the average user. Its main purpose is to support the High-Level interface (q.v.), use of which is preferable in most applications.

This section provides a detailed description of the Low-Level interface for the programmer who may wish to use it much as he or she would the FLI. As such, it presumes familiarity with the Prolog FLI. This document is not a tutorial on how to use the Prolog FLI; consult your local Prolog documentation for how to use the FLI. Programmers who wish to use JPL without having to know any of the nitty gritty details of the Low-Level interface may skip this section and read the High-Level interface section. For information about the SWI-Prolog FLI, see your local SWI-Prolog documentation.
The JPL Low-Level interface is highly SWI-Prolog specific, unlike the High-Level interface (which could potentially be implemented on top of at least some other Prolog systems).

### Supported Data Types

The Low-Level interface provides definitions for the following support classes, which are essentially "holder" classes for the corresponding data types in the FLI:

    LongHolder
      |
      +--- term_t
      |
      +--  atom_t
      |
      +--  functor_t
      |
      +--  qid_t
      |
      +--  fid_t

    PointerHolder
      |
      +--  predicate_t
      |
      +--  module_t

With the exception of predicate_t and module_t, these classes hold Java long (signed 64-bit) values, corresponding to the C types in the FLI by the same name (unsigned long values). The module_t and predicate_t classes also hold long values, but their values are understood to be C pointers (void *).

> Note. The fact that we are using signed values to represent unsigned values should not be a problem, since we are not using these values in arithmetic expressions that could cause errors as a result of casts. However, any SWI-Prolog implementation that has a word size larger than 4 bytes is not guaranteed to work correctly with this version of the Low-Level interface.

The Low-Level interface also provides the following convenience classes used to get information back to the JavaVM from Prolog:

- IntHolder
- LongHolder
- DoubleHolder
- StringHolder
- PointerHolder

These classes are for use where a SWI-Prolog FLI function takes modifiable (by reference) parameters.

### jpl.fli.Prolog

The class jpl.fli.Prolog contains a set of Java constant (static final) and static native method declarations. These declarations more or less mirror those in the header files for the FLI (in SWI-Prolog, SWI-Prolog.h), and can all be found in the C source file jpl_fli_Prolog.c.

The general rule of thumb is as follows:

- All constant and function names (with a few notable exceptions) are the same as those in the FLI, with the Prolog implementation-specific prefix (in the case of SWI-Prolog, PL_) removed. For example, the constant PL_VARIABLE in the FLI becomes just VARIABLE, and the FLI function PL_new_term_ref() becomes just new_term_ref(). A notable exception is the throw FLI function, which is renamed to _throw in the FLI; throw is a reserved word in Java.
- All the constant values are the same in the Low-Level interface as they are in the FLI.
- The signatures of FLI functions (with a few notable exceptions) are preserved in the Low-Level interface. The Low-Level interface provides the above types for this purpose.
- Read parameters of the primitive Java types (e.g., int, float, long, etc.) are preserved.
- Modify parameters of the primitive Java types take Holder classes (e.g., IntHolder, DoubleHolder, LongHolder, etc.) in which the values are written, instead of pointers to these types.
- Parameters of other types that are read and read/modify parameters in the FLI still take structures (e.g., jpl.fli.term_t) as arguments in the Low-Level interface. This preserves the signature of these methods as much as possible. A notable exception is the FLI strip_module function, which takes a module_t * as a parameter; in the Low-Level interface, the strip_module method takes a module_t, not a Holder for this type.

### Using the Low-Level Interface

Programmers already comfortable with the FLI should find no surprises. For example, to create a term_t in Java, one would do the same as one would do in C:

>     term_t t = Prolog.new_term_ref();

The difference is that the Java method is now a static native method of the Prolog class, so the syntax is slightly different than the corresponding call in C. Moreover, many of the same rules in the FLI apply to the Low-Level interface, as well. To make a term reference which contains an atom, for example, one must first create the term_t, then an atom_t, and then put the atom into the term, as in the FLI:

>     term_t term = Prolog.new_term_ref();
>     atom_t atom = Prolog.new_atom( "foo" );
>     Prolog.put_atom( term, atom );

### Caveats

There is nothing special about the Low-Level interface; it is really just a straight Java mapping of the FLI, and C programmers familiar with the FLI should have little difficulty using it. On the other hand, translating the FLI to Java raises some peculiarities that should be mentioned.

#### Sequential Term References

In the FLI, one can create sequential term references via the new_term_refs function:

>     term_t t0 = Prolog.new_term_refs( n);

Subsequent references are obtained by t0+1, t0+2, etc. However, Java does not support operator overloading, so we can't obtain subsequent term references by offsetting an initial reference. We can, however, obtain the value field of a term_t structure an compute subsequent references off that value, as in, for example, t0.value+1, t0.value+2, etc.

#### Variable-length Argument Lists

Some of the C functions in the FLI (e.g, PL_cons_functor()) take variable-length arguments, function definitions whose argument lengths are not known at compile time. However, Java has no support for such definitions; all method definitions must have determinable signatures at compile time.
JPL 1.0.1 was designed and implemented before Java acquired anonymous array syntax (in Java 1.1), which make it feasible to redefine a method to take an array of arguments in place of a variable-length argument list. Since the SWI-Prolog FLI provides alternative functions that are equivalent to these variable-length argument functions, JPL 1.0.1 implemented these. The High-Level interface exploits anonymous array syntax (e.g. when constructing a Compound), but it has not been considered necessary to revise the implementation of the Low-Level interface.

#### Currently unsupported FLI functions

A number of SWI-Prolog FLI functions are currently unsupported, and not needed by the High-Level interface, but could and might be supported in future versions (preference is likely to be given to those which can sensibly be made available to applications via the High-Level interface, or which are necessary to support future extensions to the High-Level interface).

#### Unsupportable FLI functions

Some SWI-Prolog FLI functions seem inherently unsupportable within this interface:

PL_signal()
  Java can't feasibly register a C function as s signal handler
PL_action()
  problems with the argument types and qty; some of these actions may be useful...
PL_query()
  the ARGC, ARGV, MAX_INTEGER, MIN_INTEGER options are redundant
  QUERY_VERSION might be useful...
  SYMBOLFILE ?
PL_dispatch_hook()
PL_abort_hook()
PL_abort_unhook()
PL_on_halt()
PL_agc_hook()
  these are of little value within Java (unless we can install Java methods?!)

up prev next API