Category Archives: logtalk

Writing portable Logtalk applications

Portable Logtalk applications often need to call built-in predicates whose name, arguments, and semantics differ for each supported back-end Prolog compiler. This is quite frequent as the current Prolog ISO standard only covers basic functionality. A common solution for these cases is to define a protocol abstracting common functionality and to implement this protocol in a set of objects, one for each back-end Prolog compiler. An alternative solution is to use Logtalk conditional compilation directives. As also found in some Prolog compilers (e.g. ECLiPSe, SWI-Prolog, or YAP), Logtalk supports if/1, elif/1, else/0, and endif/0 directives. The arguments of the if/1 and elif/1 directives are goals that are evaluated at compilation time, switching on and off the compilation of blocks of code. Together with the prolog read-only compiler flag, it is easy to define a single object encapsulating code for different back-end Prolog compilers. For example, assuming that your portable Logtalk application (running on GNU Prolog, SWI-Prolog, and YAP) needs access to the CPU time in seconds, you could write:

:- object(timing).
 
    :- public(cpu_time/1).
    :- mode(cpu_time(-number), one).
    :- info(cpu_time/1, [
        comment is 'Current CPU time in seconds',
        argnames is ['Seconds']]).
 
    :- if(current_logtalk_flag(prolog, gnu)).
    cpu_time(Seconds) :-
        cpu_time(Miliseconds),
        Seconds is Miliseconds/1000.
 
    :- elif(current_logtalk_flag(prolog, swi)).
    cpu_time(Seconds) :-
        Seconds is cputime.
 
    :- elif(current_logtalk_flag(prolog, yap)).
    cpu_time(Seconds) :-
        statistics(cputime, [Miliseconds, _]),
        Seconds is Miliseconds/1000.
 
    :- else.
    cpu_time(_) :-
        throw(error(resource_error(predicate), cpu_time/1)).
 
    :- endif.
 
:- end_object.

A second example, cc, can be found on the current Logtalk distribution.

The conditional compilation directives can be used anywhere, as long as they encapsulate groups of directives or predicate clauses. Both solutions, using an object per back-end Prolog compiler or a single object with conditional compilation directives, have their pros and cons. The hard work, however, is usually to find the best abstraction subsuming the diversity of implementations.


Logtalk 10th anniversary

I have been so busy in the last weeks that I simply overlooked the Logtalk 10th anniversary a few days ago! The development of Logtalk 2.x started in January 1998, and the first stable version was released in February 9, 1999. Ten years later, developing Logtalk is still fun and rewarding, thanks to all the contributions from users and Prolog implementors. Keep your feature requests and bug reports coming! Work in the next stable version is progressing nicely and, with your help, I plan to keep developing and improving Logtalk for the next ten years. If I can make a wish: don’t be shy about what you’re doing with Logtalk. Stop by the Logtalk forums, talk a bit about your applications, and share your development experience.


Making your Logtalk objects multi-threading ready

Even if you’re not currently using Logtalk high-level multi-threading support to speed up your application in your shining new multi-core hardware, it’s quite easy to make your Logtalk objects and libraries multi-threading ready. Here’s how:

First, locate all your objects defining predicates that have side-effects. For example, predicates that perform input/output operations or use the (object) dynamic database. Second, add synchronized/1 directives for those predicates. Third, well, there is not third step.

A simple example, based on the Logtalk gensym library object:

:- public(gensym/2).
:- synchronized(gensym/2).
 
gensym(Base, Unique) :-
    retract(base_(Base, OldInt)) ->
    asserta(base_(Base, NewInt)),
    number_codes(NewInt, NewCodes),
    atom_codes(NewAtom, NewCodes),
    atom_concat(Base, NewAtom, Unique).

Using the synchronized/1 directive guarantees that two or more threads concurrently calling the gensym/2 predicate will not step on each other’s toes. Synchronized predicates are silently compiled as normal predicates when using back-end Prolog compilers that don’t support multi-threading programming, so there’s no penalty when running single-threaded.


New GNU Prolog version (1.3.1)

GNU Prolog is one of my favorite Prolog compilers. True, it’s not the fastest system nor the one with most features. It’s, however, one of the free and open source Prolog compilers that more closely complies with the ISO Prolog Part 1 standard. GNU Prolog is one of the compilers I use daily to develop and check the portability of the Logtalk code base. Daniel Diaz just released version 1.3.1:

http://www.gprolog.org/

Support for this new version is already included in the latest Logtalk development version (r4695).

Prolog development tip: whenever you need to check the ISO Prolog standard and you don’t a have a copy at hand, take a look at the GNU Prolog manual. ISO Prolog predicates are clearly marked and described in detail (including template, modes, and exception terms).


Revamped Logtalk “report” compiler option

The next Logtalk stable release will feature a revamped report compiler option. A new option value, warnings, reduces compilation reporting to warnings. If your Logtalk application comprises a large number of source files, defining a large number of entities, I suspect that you will appreciate the simplified compilation reports. If you don’t want to wait for the next stable release, the new warnings option is already available in the current development version.


Porting Prolog programs to Logtalk

I’m currently porting John Fletcher’s XML Parser to Logtalk. I’m also considering porting P-FLAT, Artur Dias and Michel Wermelinger’s toolkit for formal languages and automata theory. The ports are easy although more time consuming that I wished for. Given that Logtalk assumes a ISO Prolog compliant compiler underneath, the original Prolog programs must have all proprietary Prolog calls replaced by their ISO counterparts; that’s the price you pay for the broad compatibility of Logtalk with most Prolog compilers in use today.

It’s clear to me, given these current and past port exercises, that broad sharing of Prolog code between implementations suffers from both weak ISO Prolog standards and lack of knowledge of the current standards by Prolog programmers. Work on improving the current standards is underway but also undermanned. Lack of knowledge of the current standards can be partially explained by the simple fact that the ISO documents are only available for a fee (there is also a nice book on the ISO Prolog standard by P. Deransart, A. Ed-Dbali, and L. Cervoni). Another possible explanation is that most Prolog programmers do not feel a need for writing portable code. Or simply lack the perception that their code will not run and, in some cases, will not even compile, when using another Prolog implementation. This is as much as a problem with programmers as a problem with the Prolog language itself. People working with Java, Python, C#, or PHP do not face the kind of compatibility problems that plague Prolog programming.

We have a very rich Prolog ecosystem with more than two dozen implementations currently available. Even if we count only the most popular ones, their number is still close to a dozen. However, Prolog is nowadays little more than a niche language. Lack of code sharing means that Prolog programmers cannot bootstrap their applications without being trapped in some proprietary implementation, even for basic tasks. Lack of libraries and bindings for popular APIs makes choosing Prolog as an industrial tool a risky proposition, despite all the advantages when compared with other languages. Is the Prolog future bleak? I like to think that you and me can make a difference. How? By demanding better ISO Prolog compliance from Prolog implementers, by working with our local standards committee, by regularly rotating Prolog compilers when programming. Current standardization efforts include DCGs, Globals, and Threads. A revision to the core standard is also underway, fixing typos, omissions, and hopefully adding some missing built-in predicates that should have been there from the start. If you currently have an itch that needs scratching, why not find other programmers facing the same problems (Prolog mailing lists and the comp.lang.prolog newsgroup are good places to start) and write a draft proposal?