File: ReleaseNotes701.md

package info (click to toggle)
swi-prolog 9.0.4%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 82,408 kB
  • sloc: ansic: 387,503; perl: 359,326; cpp: 6,613; lisp: 6,247; java: 5,540; sh: 3,147; javascript: 2,668; python: 1,900; ruby: 1,594; yacc: 845; makefile: 428; xml: 317; sed: 12; sql: 6
file content (360 lines) | stat: -rw-r--r-- 11,987 bytes parent folder | download | duplicates (4)
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.