2.2 Non-Embedded Logic Engines
2.2.2 InterProlog
InterProlog [13, 14] allows Java programmers to pass objects to Prolog either by reference (as in JPL) or as serialised streams of bytes. At the time of writing, the publicly available version is socket-based and compatible with XSB only. Previous versions have also been compatible with SWI and YAP Prolog.
From Prolog to Java with InterProlog
On the Prolog-side, the javaMessage/2 predicate allows a programmer to send messages to a Java object. The example shown in code snippet 2.7 illus- trates how to send the message println to the static variable out in the class java.lang.System. The operator - is employed to refer to the field of an object or a static variable in a class.
1 javaMessage ( java . lang . System -out , 2 println ( string ( Hello World ! )) 3 ).
Snippet 2.5: The InterProlog javaMessage/2 predicate.
InterProlog allows to express Java objects as “object specifications”. Code snippet 2.6, extracted from [13], illustrates how a Java Integer representing the number 13 is expressed as an object specification on the Prolog-side. Such specification “corresponds to the blueprint for a new object instance on the Java-side”. In this way, InterProlog defines an automatic conversion between Java objects and Prolog terms based on the Java serialisation API [107] (on the Java-side) and a definite clause grammar [110] (on the Prolog- side). In other words, the term representation of an arbitrary Java object is derived from its serialisation as a plain stream of bytes. The grammar used by InterProlog allows to obtain a more readable representation, more amenable for reasoning and pattern matching in Prolog.
1 IntegerObject = object (
3 classDescInfo ([ int( value )],2,
4 class ( java . lang .Number , long ( -31060 , -27363 ,2964 , -8053) ,
5 classDescInfo ([] ,2 , null )))),
6 [] + [] + [13]) ;
Snippet 2.6: An object specification in InterProlog.
InterProlog allows to start and manipulate Prolog engines from Java programs by means of instances of a class reifying a Prolog engine. Alter- natively, Prolog engines are also reified on the Prolog-side: it is possible to obtain a term representing the current Prolog engine. Therefore, on the Prolog-side the term representation of the executing Prolog engine can be passed to the Java-side as a method or constructor argument. This facilitates the inversion of the control towards the object-oriented world and the creation of programs that may need to interact with more than one Prolog engine.
Code snippet 2.7 illustrates an example of this feature. A representation of the current Prolog engine is obtained by means of the ipPrologEngine /1 predicate. Afterwards, it is sent as an argument to the constructor of the HelloWindow class defined on the Java-side. The implementation of this class is shown in the next section.
1 ipPrologEngine ( Engine ), JavaMessage ( HelloWindow , HelloWindow ( Engine )).
Snippet 2.7: The InterProlog javaMessage/2 predicate.
From Java to Prolog with InterProlog
Code snippet 2.8 shows the implementation of the HellowWindow class intro- duced in the previous section. As described before, the class expects an object reifying a Prolog engine in its constructor (line 3).
This example illustrates how InterProlog manages Java references on the Prolog-side. A JTextField component is instantiated (line 6) and is explicitly registered as a foreign object in the Prolog engine (line 7). Lines 8 to 13 provide the code for showing a window containing the previous text field and a button using the Swing library. When the button is pushed, it queries the greatat/1 predicate, passing as argument the handler to the text field object (line 16).
1 public class HelloWindow extends JFrame { 2 PrologEngine myEngine ;
3 public HelloWindow ( PrologEngine pe) {
4 super ("Java -Prolog - Java call example ");
5 myEngine = pe;
6 JTextField text = new JTextField (15) ;
7 final Object fieldObject = myEngine . makeInvisible ( text ); 8 text . setBorder ( BorderFactory . createTitledBorder (" text ")); 9 JButton button = new JButton (" Greet ");
10 Box box = new Box( BoxLayout . Y_AXIS ); 11 box.add( text ); box.add( button ); 12 getContentPane ().add(box); 13 setSize (200 ,100) ; show ();
14 button . addActionListener ( new ActionListener () { 15 public void actionPerformed ( ActionEvent e) {
16 myEngine . deterministicGoal (" greetat (Obj)","[Obj]",new ΩÚ Object []{ fieldObject }); 17 } 18 }); 19 } 20 }
Snippet 2.8: From Java to Prolog example with InterProlog.
The definition of the greatat/1 predicate is shown in code snippet 2.9. The predicate invokes the Java method setText on the text field reference received as argument. The argument of the setText method is the string “Hello World!”, which will be shown in the text field when the greatat/1 predicate is queried. Note that a Java string is expressed with the compound string/1.
1 greetat ( _Text ) :- JavaMessage ( _Text , setText ( string ( Hello world ! )) )
Snippet 2.9: Sending a message to an object reference with InterProlog.
InterProlog Summary
Although InterProlog provides automatic conversions from Java objects to Prolog terms and vice-versa, a programmer has no control over the term rep- resentation of such Java objects. Instead, a fixed object-specification built from the serialised object data is employed. This technique has the disadvantage that it can only work with objects implementing the Java java.io.Serializable interface, which limits to a certain extent its applicability. An advantage of the serialisation-based technique of InterProlog, however, is that it works out of the box with objects having circular references (e.g., an object having itself as one of its properties).
An advantage of expressing Java Strings by means of the string/1 com- pound consists in simple atoms being free to be used to reference Java classes, as illustrated by code snippet 2.7. However, an inconvenience of this design decision consists in calls to methods including Java Strings as arguments are less straightforward and concise.
From a functionality perspective, a limitation of InterProlog is that it does not support non-deterministic queries. Instead, if a programmer requires more solutions than the first one, she is forced to rely on meta-predicates such as findall/3 for getting all the solutions to a query. This is quite inefficient in many scenarios (i.e., the query may demand a considerable amount of time to process all solutions when the programmer was interested in only a small subset of them).