10.2 Executable objects

PCE defines executable objects. Executable objects (called code objects) can be compared to lambda functions in Lisp. They are used in the contexts given below.

Two major groups of code objects are distinguished: procedures and functions. The first only returns status information similar to the send-operation. The latter returns a value or failure status information similar to the get-operation.

10.2.1 Procedures

Procedures perform an action when executed. Similar to Prolog, the execution of a procedure either returns successful or failed completion. Procedures are normally executed by the object or method they are handed to. For example, the procedure associated to a button object is executed when the button is pressed. The procedure handed to the `chain->for_all' method we have seen above is executed by this method for each element of the chain.

Procedures can also be executed explicitly using the method `code->forward'. This binds the argument-forwarding objects @arg1, ..., and then executes the procedure and restores the old bindings of argument-forwarding objects. For example:

1 ?- new(@m, message(@prolog, format, 'Hello ~w~n', @arg1)).
2 ?- send(@m, forward, world).
Hello world

The online manual may be used to get an overview of the other available code objects. See section 3.3.4.

10.2.2 Functions

Functions are code objects which ---when executed--- evaluate to a value. They are commonly used as arguments to other code objects or as arguments to any method. A function is automatically evaluated iff:

The most important function objects are:

10.2.3 Example 1: Finding objects

A common problem is to find objects, notably some specific graphical object on a window. If we want to find all instances of class box within a graphical device, we can use the call below, collecting all boxes on the device in a new chain.

        ...
        get(Dev?graphicals, find_all.
            message(@arg1, instance_of, box),
            Boxes),
        ...

10.2.4 Example 2: Internal behaviour of dialog window

Code are most commonly used to specify the internal behaviour of dialog windows, such that the call-back predicate can concentrate on the real function. We have seen an example of this in section 2.8.

Below there is another example. Data is assumed to be an XPCE string object containing a PostScript® description of a graphical object as can be obtained using

        ...,
        get(Graphical, postscript, PostScriptString),
        ...,

In this example both the internal dynamics of the dialog window (the label of the text-entry fields changes if the user switches from file to printer) and grabbing the arguments from the various dialog items is written using XPCE executable objects. Prolog will only be called to do the real work: printing the data to the requested destination.

Note that XPCE/Prolog does not require you to use XPCE executable objects this way. It is also possible to call Prolog from both the menu and the buttons, passing the dialog window as argument and write all behaviour in Prolog. We leave this as an exercise to the user.

postscript(Data) :-
        new(D, dialog('Print destination')),
        send(D, append, new(T, menu(destination, marked))),
        send_list(T, append, [printer, file]),
        send(T, layout, horizontal),
        send(D, append,
             new(A, text_item(printer_name, 'PostScript'))),
        send(T, message,
             if(T?selection == printer,
                message(A, label,
                        ?(A, label_name, printer_name)),
                message(A, label,
                        ?(A, label_name, file_name)))),
        send(D, append,
             button(ok, and(message(@prolog,
                                    print_postscript,
                                    T?selection,
                                    A?selection,
                                    Data),
                            message(D, destroy)))),
        send(D, append,
             button(cancel, message(D, destroy))),
        send(D, default_button, ok),
        send(D, open).
          
print_postscript(printer, Address, Data) :- !,
        new(F, file),
        send(F, open, write),
        send(F, append, Data),
        send(F, close),
        get(F, name, TmpFile),
        get(string('lpr -P%s %s', Address, TmpFile),
            value, Command),
        unix(shell(Command)),     
        send(F, remove).
print_postscript(file, Address, Data) :-
        new(F, file(Address)),
        send(F, open, write),
        send(F, append, Data),
        send(F, close).

Figure 15 : Print destination dialog using code objects for internal behaviour