This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/Logtalk/manuals/migration/index.html

156 lines
17 KiB
HTML
Raw Normal View History

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="content-type" content="application/xml+xhtml; charset=utf-8" />
<title>Logtalk: Prolog Integration and Migration Guide</title>
<link rel="stylesheet" href="../print.css" type="text/css" media="print"/>
<link rel="stylesheet" href="../screen.css" type="text/css" media="screen"/>
</head>
<body>
<div class="navtop"><span><a href="../index.html">contents</a></span> &gt;
<span class="title">Prolog Integration and Migration Guide</span><span class="page"/>
</div>
<h1>Prolog Integration and Migration Guide</h1>
<p>
An application may include plain Prolog files, Prolog modules, and Logtalk objects. This is a perfectly valid way of developing a complex application and, in some cases, it might be the most appropriated solution. Modules may be used for legacy code or when a simple encapsulation mechanism is adequate. Logtalk objects may be used when more powerful encapsulation, abstraction, and reuse features are needed. Logtalk supports the compilation of source files containing both plain Prolog and Prolog modules. This guide provides tips for helping integrating and migrating plain Prolog code and Prolog module code to Logtalk. Step-by-step instructions are provided for encapsulating plain Prolog code in objects, converting Prolog modules into objects, and compiling and reusing Prolog modules as objects from inside Logtalk. An interesting application of the techniques described in this guide is a solution for running a Prolog application which uses modules on a Prolog compiler with no module system.
</p>
<h2>Source files with both Prolog code and Logtalk code<a id="hybrid"></a></h2>
<p>
Logtalk source files may contain plain Prolog code intermixed with Logtalk code. The Logtalk compiler just copies the plain Prolog code as-is to the generated Prolog file. With Prolog modules, it is assumed that the module code starts with a <code>module/1-2</code> directive and ends at the end of the file. There is no module ending directive which would allowed us define more than one module per file. In fact, most Prolog module systems always define a single module per file. Some of them mandate that the <code>module/1-2</code> directive be the first term on a source file. As such, when the Logtalk compiler finds a <code>module/1-2</code> directive, it assumes that all code that follows until the end of the file belongs to the module.
</p>
<h2>Encapsulating plain Prolog code in objects<a id="encapsulating"></a></h2>
<p>
Most applications consist of several plain Prolog source files, each one defining a few top predicates and auxiliary predicates that are not meant to be directly called by the user. Encapsulating plain Prolog code in objects allows us to make clear the different roles of each predicate, to hide implementation details, and to take advantage of other Logtalk features.
</p>
<p>
Encapsulating Prolog code using Logtalk objects is easy. First, for each source file, add an opening object directive, <a title="Consult reference manual" href="../refman/directives/object1_5.html"><code>object/1</code></a>, to the beginning of the file and an ending object directive, <a title="Consult reference manual" href="../refman/directives/end_object0.html"><code>end_object/0</code></a>, to end of the file. Choose an object name that reflects the purpose of source file code (this is a good opportunity to reorganize your code if needed). Second, add <a title="Consult reference manual" href="../refman/directives/public1.html">public predicate directives</a> for the top-level predicates that are used directly by the user or called from other source files. Third, we need to be able to call from inside an object a predicate defined in other source file/object. The easiest solution, which has the advantage of not implying any modification to the predicate clauses, is to use the <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directive. If your Prolog compiler supports cross-referencing tools, you may use them to help you make sure that all calls to predicates on other source files/objects are listed in the <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directives. Compiling the resulting objects with the Logtalk <code>portability</code> flag set to <code>warning</code> will help you locate calls to predicates defined on other converted source files.
</p>
<h3>Prolog multifile predicates</h3>
<p>
Prolog multifile predicates are used when clauses for the same predicate are spread among several source files. When encapsulating plain Prolog code that uses multifile predicates, is often the case that the clauses of the multifile predicates get spread between different objects and categories. When calling such predicates, you often want to use not only local clauses but also clauses stored in ancestor objects or imported. However, these <em>inherited</em> clauses are overridden by the local ones. For ancestor objects, use the <em>super call</em> operator, <code>^^/1</code>, to get access to the overridden clauses. For imported categories, use the <em>message to self</em> operator, <code>::/1</code>, to get access to the overridden clauses. For example, assume a multifile predicate, <code>mp/2</code> with both local clauses and clauses imported from a category. The solution is to add a local clause giving access to the imported clauses by using the <code>::/1</code> operator:
</p>
<pre>
mp(..., ...). % local clauses
...
mp(A, B) :- % imported clauses
::mp(A, B).
</pre>
<p>
By adding the <em>gateway</em> clause after or before the local clauses, you can choose if the local clauses should be used before or after the overridden clauses.
</p>
<h2>Converting Prolog modules into objects<a id="converting"></a></h2>
<p>
Converting Prolog modules into objects allows an application to run on a wider range of Prolog compilers, overcoming module compatibility problems. Not all Prolog compilers support a module system. Among those Prolog compilers which support a module system, the lack of standardization leads to several issues, specially with operators and meta-predicates. In addition, the conversion allows you to take advantage of Logtalk more powerful abstraction and reuse mechanisms such as separating interface from implementation.
</p>
<p>
Converting a Prolog module into an object is easy as long as the directives used in the module are supported by Logtalk (see below). First, convert the module <code>module/1</code> directive into an opening object directive, <a title="Consult reference manual" href="../refman/directives/object1_5.html"><code>object/1</code></a>, using the module name as the object name. For <code>module/2</code> directives apply the same conversion and convert the list of exported predicates into Logtalk <a title="Consult reference manual" href="../refman/directives/public1.html">public predicate directives</a>. Second, add a closing object directive, <a title="Consult reference manual" href="../refman/directives/end_object0.html"><code>end_object/0</code></a>, at the end of the module code. Third, convert any <code>export/1</code> directives into public predicate directives. Fourth, convert any <code>use_module/2</code> directives into Logtalk <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directives. Any <code>use_module/1</code> directives are also converted into Logtalk <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directives but you will need first to find out which predicates your module uses from the specified modules. Fifth, convert any <code>meta_predicate/1</code> directives into Logtalk <a title="Consult reference manual" href="../refman/directives/meta_predicate1.html"><code>meta-predicate/1</code></a> directives by replacing the module meta-argument indicator, <code>:</code>, into the Logtalk meta-predicate indicator, <code>::</code>. Arguments which are not meta-arguments are represented by the <code>*</code> character. Compile the resulting objects with the Logtalk <code>portability</code> flag set to <code>warning</code> to help you locate calls to predicates defined on other converted modules.
</p>
<h2>Compiling Prolog modules as objects<a id="compiling"></a></h2>
<p>
An alternative to convert Prolog modules into objects is to just compile the modules as objects. This has the advantage of not implying any code changes. However, this is only possible for modules containing only predicates clauses and Logtalk supported directives (see below). Assuming that is the case, you may compile a Prolog module as an object by changing the source file name extension to <code>.lgt</code> and then using the <a title="Consult user manual" href="../userman/running.html#compiling"><code>logtalk_load/1-2</code></a> and <a title="Consult user manual" href="../userman/running.html#compiling"><code>logtalk_compile/1-2</code></a> predicates (set the Logtalk <code>portability</code> flag set to <code>warning</code> to help you catch any unnoticed cross-module predicate calls). This allows you to reuse existing module code as objects. However, there are some limitations that you should be aware. These limitations are a consequence of the lack of standardization of Prolog module systems. Currently, Logtalk supports the following module directives:
</p>
<dl>
<dt><code>module/1</code></dt>
<dd>The module name becomes the object name.</dd>
<dt><code>module/2</code></dt>
<dd>The module name becomes the object name. The exported predicates become public object predicates.</dd>
<dt><code>use_module/2</code></dt>
<dd>This directive is compiled as a Logtalk <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directive in order to ensure correct compilation of the module predicate clauses. Note that the module specified on the directive is not automatically loaded by Logtalk (as it would be when compiling the directive using Prolog instead of Logtalk; the programmer may also want the specified module to be compiled as an object).</dd>
<dt><code>export/1</code></dt>
<dd>Exported predicates are compiled as public object predicates. The argument must be a predicate indicator (<code>Functor/Arity</code>) or a list of predicate indicators.</dd>
<dt><code>meta_predicate/1</code></dt>
<dd>Module meta-predicates become object meta-predicates. Only predicate arguments marked as <code>:</code> are interpreted as meta-arguments. However, note that Prolog module meta-predicates and Logtalk meta-predicates don't share the same exact semantics; check results carefully.</dd>
</dl>
<p>
Logtalk supports the use of the <a title="Consult user manual" href="../userman/programming.html#programming_libraries"><em>library(name)</em> notation</a> on the <code>module/1-2</code> and <code>use_module/2</code> directives (assuming there is an entry for the library on the <a title="Consult reference manual" href="../refman/builtins/logtalk_library_path2.html"><code>logtalk_library_path/2</code></a> table).
</p>
<p>
When compiling modules as objects, you probably don't need event support turned on. Thus, you may want to use the compiler option <code>events(off)</code> with the Logtalk compiling and loading built-in methods for a small performance gain for the compiled code.
</p>
<h3>Current limitations and workarounds<a id="limitations"></a></h3>
<p>
Note that <code>use_module/1</code> directives are not directly supported. Therefore, this directives must be converted into <code>use_module/2</code> directives by finding which predicates exported by the specified module are imported into the module containing the directive. Automating the conversion would imply loading the module without re-interpreting it as an object, which might not be what the user intended. Nevertheless, finding the names of the imported predicates is easy. First, comment out the <code>use_module/1</code> directives and compile the file (making sure that the compiler flag <code>misspelt</code> is set to <code>warning</code>). Logtalk will print a warning with a list of predicates that are called but never defined. Second, use these list to replace the <code>use_module/1</code> directives by <code>use_module/2</code> directives. You should then be able to compile the modified Prolog module as an object.
</p>
<p>
Changing the extension of a module source file to <code>.lgt</code> in order to be able to compile it as Logtalk source file is not always feasible. An alternative is to create symbolic links or shortcuts for the module files using <code>*.lgt</code> names. In addition, for avoiding conflicts between the Logtalk generated Prolog files and the module files, create the links on a different directory and add a library entry for the directory using the predicate <a title="Consult reference manual" href="../refman/builtins/logtalk_library_path2.html"><code>logtalk_library_path/2</code></a>. For example, on a POSIX operating-system with <code>library/*.pl</code> module source file names, the links can be easily created by running the following bash shell commands:
</p>
<pre>$ mkdir lgtlib
$ cd lgtlib
$ for i in ../library/*.pl; do ln -sf $i `basename $i .pl`.lgt; done</pre>
<p>
The symbolic links or shortcuts can also be easily created on most operating-systems using the GUI tools.
</p>
<h2>Dealing with proprietary Prolog directives<a id="proprietary"></a></h2>
<p>
Most Prolog compilers define proprietary, non-standard directives that may be used in both plain code and module code. Logtalk will generate compilation errors on source files containing these directives unless you first specify how the directives should be handled. Three actions are possible and can be specified, on a per-directive basis, on the Prolog configuration files: ignoring the directive (i.e. do not copy the directive, although a goal can be proved as a consequence), rewriting and copy the directive to the generated Prolog files, or rewriting and recompiling the resulting directive. Each action is specified using, respectively, the predicates: <code>'$lgt_ignore_pl_directive'/1</code>, <code>'$lgt_rewrite_and_copy_pl_directive'/2</code>, and <code>'$lgt_rewrite_and_recompile_pl_directive'/2</code>. For example, assume that a given Prolog compiler defines a <code>comment/2</code> directive for predicates using the format:
</p>
<pre>:- comment(foo/2, "Brief description of the predicate").</pre>
<p>
We can rewrite this predicate into a Logtalk <code>info/2</code> directive by defining a suitable clause for the <code>'$lgt_rewrite_and_recompile_pl_directive'/2</code> predicate:
</p>
<pre>'$lgt_rewrite_and_recompile_pl_directive'(comment(F/A, String), info(F/A, [comment is Atom])) :-
atom_codes(Atom, String).</pre>
<p>
This Logtalk feature can be used to allow compilation of legacy Prolog code without the need of changing the sources. When used, is advisable to set the <code>portability/1</code> compiler flag to <code>warning</code> in order to more easily identify source files that are likely non-portable across Prolog compilers.
</p>
<p>
A second example, using the <code>'$lgt_ignore_pl_directive'/1</code> hook predicate:
</p>
<pre>'$lgt_ignore_pl_directive'(load_foreign_files(Files,Libs,InitRoutine)) :-
load_foreign_files(Files,Libs,InitRoutine).</pre>
<p>
In this case, although the directive is not copied to the generated Prolog file, the foreign library files are loaded as a side-effect of calling the hook predicate.
</p>
<h2>Calling Prolog module predicates using message sending<a id="calling"></a></h2>
<p>
Logtalk allows you to send a message to a module in order to call one of its predicates. This is usually not advised as it implies a performance penalty when compared to just using the <code>Module:Call</code> notation (encapsulating the call between curly brackets when sending the message from inside an object). Note that this only works if there is no object with the same name as the module you are targeting.
</p>
<p>
This feature is needed to properly support compilation of modules containing <code>use_module/2</code> directives as objects. If the modules specified in the <code>use_module/2</code> directives are not compiled as objects but are instead loaded as-is by Prolog, the exported predicates would need to be called using the <code>Module:Call</code> notation but the converted module will be calling them through message sending. Thus, this feature ensures that, on a module compiled as an object, any predicate calling other module predicates will work as expected either these other modules are loaded as-is or also compiled as objects.
</p>
<div class="footer">
<div class="copyright">
<span>Copyright &copy; <a href="mailto:pmoura@logtalk.org">Paulo Moura</a> &mdash; <a href="http://logtalk.org">Logtalk.org</a></span><br/>
<span>Last updated on: June 6, 2007</span>
</div>
<div class="navbottom">
<span><a href="../glossary.html">glossary</a></span><br/>
<span><a href="http://validator.w3.org/check/referer">XHTML</a> + <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a></span>
</div>
</div>
</body>
</html>