1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
|
# Release notes - 7.0.1
SWI Prolog V7 maintains good source level compatibility with previous major versions,
but there are significant changes to the term model and foreign language interface (FLI),
and it is with these that JPL interfaces.
I have (eventually) prototyped a new version of JPL to serve SWI Prolog V7
in both its default and --traditional modes.
With Jan's encouragement, I have taken the opportunity to modernise JPL's APIs,
without unnecessarily complicating the migration of user applications from V6 (and earlier).
The Prolog API (jpl_call/4 etc.), which presents JVM classes and objects to Prolog,
has barely changed, as there have been no changes to the Java Native Interface (JNI)
and programming model which affect JPL's functionality. The Java language has evolved,
but most new features are compiled out, and JPL is an interface to the JVM, not to Java.
The Java API (Query.oneSolution etc.) has changed in some important ways,
and these are summarised below.
## Modern vs. traditional syntax
**summary:** *JPL7 supports --traditional mode too*
When started from Prolog, e.g. as a side-effect of
```prolog
jpl_call('java.lang.System', getProperty, ['os.arch'], X).
```
JPL7 respects the prevailing "syntax" option (modern or traditional) set when SWI Prolog was started; if you run
```
swipl --traditional ...
```
then JPL7 will automatically use traditional list syntax, otherwise it will use the (default) modern syntax.
If your application starts JPL from Java, e.g. as a side-effect of
```prolog
Query.oneSolution("current_prolog_flag(arch,A)").get("A").name()
```
then JPL7 initialises using modern syntax; you can override this by calling
```prolog
JPL.setTraditional()
```
before any JPL operation which starts or requires Prolog.
## A new Java package name
JPL7's Java API is in a new package, hence
```java
import org.jpl7.*;
```
instead of JPL 3.x's
```java
import jpl.*;
```
I am confident that this renaming will prevent much more confusion than it causes, by clearly distinguishing the old and new API and applications which use them.
The new package name is more idiomatic, and the domain has been secured for documentation etc.
## Unbounded integers
**summary:** *new backwards-compatible support for arbitrarily large integers*
JPL7 supports SWI Prolog's unbounded integers, backwards-compatibly with JPL 3.x's support for bounded
(max 64-bit twos complement) integers.
An `org.jpl7.Integer` instance can be constructed from a `java.math.BigInteger` instance
as well as from long, int, short, char or byte values.
If you do not expect Prolog to return "big" integer values (i.e. too large, +ve or -ve,
to fit into a Java long), then you can continue to use Integer as in JPL 3.x.
`Integer.longValue()` will throw a `JPLException` if its value won't fit in a long,
and you can test for and retrieve big values with
```java
i.isBig()
i.bigValue()
```
## Solutions as maps
**summary:** *Hashtable is replaced by Map<String, Term>*
In JPL7, a solution promises only to support this interface:
```java
java.util.Map<java.lang.String, org.jpl7.Term>
```
whereas in JPL 3.x it was explicitly a java.util.Hashtable (from Object to Object).
JPL7 actually returns instances of the more modern HashMap, but this is not formally documented, it could (in principle) change, and you shouldn't need to know this.
To migrate your JPL 3.x Java code to JPL7, you will need to replace
```java
Hashtable
```
by
```java
Map<String, Term>
```
if you use generics, or by
```java
Map
```
if you don't. Use of generic types will eliminate many coercions and enhance static type checking.
## Iterating one-at-a-time solutions
**summary:** *hasNext replaces hasMoreSolutions etc.*
`org.jpl7.Query` supports one-at-a-time solution fetching by implementing the `Iterable` and `Iterator` interfaces;
a `Query` instance is its own `Iterator`, hence
```java
for (Map soln : new Query("current_module(X)")) {
... soln.get("X").name() ...
}
```
or
```java
Query q = new Query(current_module(X)"));
while (q.hasNext()) {
... q.next().get("X").name() ...
}
```
The following JPL 3.x `Query` methods have been removed:
```java
q.hasMoreElements()
q.nextElement()
q.hasMoreSolutions()
q.nextSolution()
```
Use the corresponding methods from the `Iterator` interface instead:
```java
q.hasNext()
q.next()
```
In this respect, migrating JPL 3.x applications to JPL7 should require only shallow textual editing (flagged by the compiler), not structural changes.
## Iterating aggregated solutions
**summary:** *no change here*
JPL's `Query.allSolutions()` and `.nSolutions()` are analogous to SWI Prolog's `findall/3` and `findnsolns/3`.
Note that what JPL calls a *solution* is strictly a *substitution*, i.e. a map from variables to bindings.
Nevertheless, JPL7 and its documentation will continue to use *solution* everywhere.
In JPL7, these `Query` methods (still) return an array of solutions;
in current Java best practice they should arguably use `java.util.List` from the Collections Framework,
but I can see no overall advantage in changing this.
Note that Java arrays can be iterated with the *for-each* construct:
```java
for (Map soln : Query.allSolutions("current_module(X)")) {
... soln.get("X").name() ...
}
```
## Atom is a direct subclass of Term
**summary:** *Term class hierarchy flattened to reflect reality better*
In JPL 3.x, `Atom` extended `Compound`; it was a specialised compound with no args.
```
Term
+-- Compound
| +-- Atom
```
in JPL7, `Atom` and `Compound` are sibling subclasses of `Term`,
because SWI Prolog V7 compounds may have zero args yet be distinct from similarly named atoms,
and JPL7 `Atom` instances have extra structure and functionality;
there is no longer any inheritance worth representing.
```
Term
+-- Compound
+-- Atom
|
```
Migrating your JPL 3.x Java code to JPL7 requires recoding situations (if any) which exploit this inheritance.
The Java compiler should flag these for you, and the impact is local (albeit not a simple global edit).
## New types of Atom
**summary:** *atoms are backwards-compatibly typed, embracing strings and (some) blobs*
Classic Prolog atoms are equal iff their string names are equal, end of story (almost).
SWI Prolog has long had strings and blobs as well as classic atoms, and V7 builds on this.
JPL7 atoms have two internal components:
```java
String name; // as in JPL 3.x
String type; // new in JPL7
```
For traditional atoms, the type is `"text"`.
For out-of-band special atoms, such as the V7 empty list, the type is `"reserved_symbol"`, as in JPL7 source code
```java
protected static final Atom LIST_NIL_MODERN = new Atom("[]", "reserved_symbol");
public static Atom LIST_NIL = LIST_NIL_MODERN; // unless we switch to --traditional
```
SWI Prolog V7 strings are represented in JPL7 as `Atom` instances whose type is `"string"`;
if you don't bother to check this, strings appear to be returned from Prolog as "text" atoms
which may be convenient (or misleading).
Note that type is currently a `java.lang.String`, not a symbolic constant or enum.
This is because SWI Prolog supports user-defined blob types with arbitrary user-defined names,
although JPL7 doesn't (yet) handle these.
## List support
**summary:** *update explicit uses of ./2 and []/0, preferably using LIST_PAIR and LIST_NIL*
In SWI Prolog V7, lists are not an ADT. Although the empty list is denoted by an out-of-band atom
```java
new Atom("[]", "reserved_symbol")
```
the list pair constructor is a regular functor
```java
new Compound("[|]", new Term[] {....})
```
which (to me) means that V7 lists are still just a term encoding convention, as in classic Prolog.
Note also that
```prolog
[a|_]
[a|b]
```
are valid structures which do not map comfortably to instances of (say) `java.util.List<Term>`.
For these reasons taken together, JPL7 passes lists as regular terms,
and provides utilities to convert to and from various Java classes.
If your Java code manipulates lists, use the new symbols and methods e.g.
```java
new Compound(JPL.LIST_PAIR, new Term[],{ myTerm, JPL.LIST_NIL })
if (soln.get("X").isListNil()) {
```
## Dict support
**summary:** *not yet implemented or finally designed; aiming to be future-proof*
The SWI Prolog V7 *dict* is an abstract data type (ADT), currently implemented using an out-of-band functor
and a conventional, may-change internal structure.
JPL7 proposes to support dicts with a new subclass of `Term` containing a name and wrapping
(or otherwise impersonating) a map, hence (in pseudo code)
```java
new Dict(Map<Term, Term> map) // construct an anonymous dict
new Dict(String name, Map<Term, Term> map) // construct a named dict
dict.name() // null if dict is anonymous
dict.get(Term key)
```
Note that: dict keys must currently be either (textual) atoms or (small) integers; the map is necessarily from `Term` to `Term`; JPL7 must check (at run-time) that all keys are legitimate.
This is *not yet implemented*, and constructive discussion is welcomed.
## Replaced in JPL7
**summary:** *a few names and types have changed*
gone | replacement
---- | -----------
import jpl.*; | import org.jpl7.*;
Hashtable | Map<String, Term>
Query.hasMoreElements() | Query.hasNext() or for-each
Query.nextElement() | Query.next() or for-each
Query.hasMoreSolutions()| Query.hasNext() or for-each
Query.nextSolution()| Query.next() or for-each
## Absent from JPL7, deprecated in JPL 3.x
**summary:** *several deprecated methods have been removed*
gone | replacement
---- | -----------
Query.name() | Query.goal().name()
Query.args() | Query.goal().args()
Query.rewind() | Query.close()
Query.query() | Query.hasSolution()
Query.debugString() |
Term.debugString() | (feel free to improvise)
Float.value() | Float.doubleValue()
Float.floatValue() |
Integer.value() | Integer.longValue()
Integer.intValue() |
## Absent from JPL7, disfunctional in JPL 3.x
**summary:** *Query.abort() has gone (for now)*
Some JPL 3.x features have simply been dropped, when arguably they should have been fixed.
gone | rationale
---- | ---------
Query.abort() | it never worked
## Term method orthogonality
**summary:** *all Term subclasses support all methods, reducing need for coercions*
For coding convenience, the major methods of `Term`'s concrete subclasses
(`Atom`, `Compound`, `Integer`, `Float`, `Variable` and (soon) `Dict`) are supported in JPL7
by all these classes; this reduces the need for coercions.
method | Atom | Compound | Float | Integer | Variable
------ | ---- | -------- | ----- | ------- | --------
arg(int) | | | | |
args() | | | | |
arity() | | | | |
bigValue() | | | | |
blobType() | | | | |
doubleValue() | | | | |
equals() | | | | |
floatValue() | | | | |
hasFunctor(double, int) | | | | |
hasFunctor(String, int) | | | | |
hasFunctor(int, int) | | | | |
isAtom() | | | | |
isCompound() | | | | |
isFloat() | | | | |
isInteger() | | | | |
isJFalse() | | | | |
isJNull() | | | | |
isJObject() | | | | |
isJRef() | | | | |
isJTrue() | | | | |
isJVoid() | | | | |
isListNil() | | | | |
isListPair() | | | | |
isVariable() | | | | |
jrefToObject() | | | | |
listLength() | | | | |
longValue() | | | | |
name() | | | | |
toString() | | | | |
toTermArray() | | | | |
type() | | | | |
typeName() | Atom | Compound | Float | Integer | Variable
## Some things which haven't been modernised
**summary:** *a few, harmless legacy oddities have been preserved*
JPL7's `Query.allSolutions()` should perhaps return a `java.util.List` of solutions (following the way of
the Collections Framework) but I've decided to maintain the JPL 1.x tradition of returning an array.
Note that arrays can be iterated with for-each
```java
for (Map soln : Query.allSolutions("p(X)")) {
... soln.get("X") ...
}
```
Term accessors should perhaps all have method names beginning with "get",
```java
t1.getArity()
t2.getName()
t3.getFloatValue()
```
but for now we keep the (concise but un-Java-idiomatic) naming from prior JPL.
|