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/userman/messages.html

287 lines
14 KiB
HTML
Raw Normal View History

<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/css" href="../styles.css" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>Logtalk user manual: message sending</title>
<link rel="stylesheet" href="../styles.css" type="text/css" />
</head>
<body>
<div class="navtop">
<a href="../index.html">contents</a> &gt; <a href="index.html">user manual</a>
</div>
<h1>Message sending</h1>
<p>
Note that message sending is only the same as calling an object's predicate if the object does not inherit (or import) predicate definitions from other objects (or categories). Otherwise, the predicate definition that will be executed may depend on the relationships of the object with other Logtalk entities.
</p>
<h2>Operators used in message sending<a name="operators"></a></h2>
<p>
Logtalk uses the following three operators for message sending:
</p>
<pre>
:- op(600, xfx, ::).
:- op(600, fx, ::).
:- op(600, fx, ^^).
</pre>
<p>
It is assumed that these operators remain active (once the Logtalk preprocessor and runtime files are loaded) until the end of the Prolog session (this is the usual behaviour of most Prolog compilers). Note that these operator definitions are compatible with the pre-defined operators in the Prolog ISO standard.
</p>
<h2>Sending a message to an object<a name="sending"></a></h2>
<p>
Sending a message to an object is accomplished by using the <a title="Consult reference manual" href="../refman/control/to_object2.html"><code>::/2</code></a> infix operator:
</p>
<pre>
| ?- Object::Message.
</pre>
<p>
The message must match a public predicate declared for the receiving object or a Logtalk/Prolog built-in predicate, otherwise an exception will be thrown (see the Reference Manual for details).
</p>
<h2>Broadcasting<a name="broadcasting"></a></h2>
<p>
In the Logtalk context, broadcasting is interpreted as the sending of the same message to a group of objects or the sending of several messages to the same object. Both needs can be achieved by using the message sending method described above. However, for convenience, Logtalk implements an extended syntax for message sending that makes programming easier in these situations.
</p>
<p>
If we wish to send several messages to the same object, we can write:
</p>
<pre>
| ?- Object::(Message1, Message2, ...).
</pre>
<p>
This is semantically equivalent to:
</p>
<pre>
| ?- Object::Message1, Object::Message2, ... .
</pre>
<p>
We can also write:
</p>
<pre>
| ?- Object::(Message1; Message2; ...).
</pre>
<p>
This will be semantically equivalent to writing:
</p>
<pre>
| ?- Object::Message1; Object::Message2; ... .
</pre>
<p>
To send the same message to a set of objects we can write:
</p>
<pre>
| ?- (Object1, Object2, ...)::Message.
</pre>
<p>
This will have the same semantics as:
</p>
<pre>
| ?- Object1::Message, Object2::Message, ... .
</pre>
<p>
If we want to use backtracking to try the same message over a set of objects we can write:
</p>
<pre>
| ?- (Object1; Object2, ...)::Message.
</pre>
<p>
This will be equivalent to:
</p>
<pre>
| ?- Object1::Message; Object2::Message; ... .
</pre>
<h2>Sending a message to <em>self</em><a name="self"></a></h2>
<p>
While defining a predicate, we sometimes need to send a message to <em>self</em>, i.e., to the same object that has received the original message. This is done in Logtalk through the <a title="Consult reference manual" href="../refman/control/to_self1.html"><code>::/1</code></a> prefix operator:
</p>
<pre>
::Message
</pre>
<p>
We can also use the broadcasting constructs with this operator:
</p>
<pre>
::(Message1, Message2, ...)
</pre>
<p>
or:
</p>
<pre>
::(Message1; Message2; ...)
</pre>
<p>
The message must match a public or protected predicate declared for the receiving object, a private predicate within the scope of the <em>sender</em>, or a Logtalk/Prolog built-in predicate otherwise an error will be thrown (see the Reference Manual for details). If the message is sent from inside a category or if we are using private inheritance, then the message may also match a private predicate.
</p>
<h2>Calling an overridden predicate definition<a name="super"></a></h2>
<p>
When redefining a predicate, sometimes we need to call the inherited definition in the new code. This possibility, introduced by the Smalltalk language through the <code>super</code> primitive, is available in Logtalk through the <a title="Consult reference manual" href="../refman/control/to_super1.html"><code>^^/1</code></a> prefix operator:
</p>
<pre>
^^Predicate
</pre>
<p>
Most of the time we will use this operator by instantiating the pattern:
</p>
<pre>
Predicate :-
..., % do something
^^Predicate, % call inherited definition
... . % do something more
</pre>
<h2>Message sending and event generation<a name="events"></a></h2>
<p>
Every message sent using <a title="Consult reference manual" href="../refman/control/to_object2.html"><code>::/2</code></a> operator generates two events, one before and one after the message execution. Messages that are sent using the <a title="Consult reference manual" href="../refman/control/to_self1.html"><code>::/1</code></a> (message to <em>self</em>) operator or the <a title="Consult reference manual" href="../refman/control/to_super1.html"><code>^^/1</code></a> super mechanism described above do not generate any events. The rational behind this distinction is that messages to <em>self</em> and <em>super</em> calls are only used indirectly in the definition of methods or to execute aditional messages with the same target object (represented by <em>self</em>). In other words, events are only generated when using an object's public interface. They can not be used to break object encapsulation.
</p>
<p>
If we need to generate events for a public message sent to <em>self</em>, then we just need to write something like:
</p>
<pre>
Predicate :-
...,
self(Self), % get self reference
Self::Message, % send a message to self using ::/2
... .
</pre>
<p>
If we also need the sender of the message to be other than the object containing the predicate definition, we can write:
</p>
<pre>
Predicate :-
...,
self(Self), % get self reference
{Self::Message}, % send a message to self using ::/2
... . % sender will be the pseudo-object user
</pre>
<p>
See the session on <a href="events.html">Event-driven programming</a> for more details.
</p>
<h2>Message sending performace<a name="performance"></a></h2>
<p>
Logtalk implements dynamic binding, coupled with a cache mechanism which avoids repeated lookups of predicate declarations and predicate definitions for the same messages. This is a solution common to other programming languages supporting dynamic binding. Message lookups are automatically cached the first time a message is sent. Cache entries are automatically removed when loading entities or using Logtalk dynamic features which invalidates the cached lookups.
</p>
<p>
When discussing Logtalk message sending performance, two distinct cases should be considered: messages sent by the user from the top-level interpreter and messages sent from compiled objects. In addition, the message declaration and definition lookups may, or may not be already cached by the runtime engine. In what follows, we will assume that the message lookups are already cached.
</p>
<h3>Translating message processing to predicate calls<a name="inferences"></a></h3>
<p>
In order to better understand the performance tradeoffs of using Logtalk when compared to plain Prolog or to Prolog module systems, is useful to translate message processing in terms of predicate calls. However, in doing this, we should keep in mind that the number of predicate calls is not necessarily proportional to the time taken to execute them.
</p>
<p>
A message sent from a compiled object to another object translates to six predicate calls:
</p>
<blockquote>
<dl>
<dt>cache lookup</dt>
<dd>one predicate call to a dynamic table</dd>
<dt>checking for <em>before</em> events</dt>
<dd>two predicate calls assuming that no events are defined</dd>
<dd>(one of them to the built-in predicate \+/1)</dd>
<dt>method call</dt>
<dd>one predicate call</dd>
<dt>checking for <em>after</em> events</dt>
<dd>two predicate calls assuming that no events are defined</dd>
<dd>(one of them to the built-in predicate \+/1)</dd>
</dl>
</blockquote>
<p>
Given that events can be dynamically defined at runtime, there is no room for reducing the number of predicate calls without turning off support for event-driven programming. When events are defined, the number of predicate calls grows proportional to the number of events and event handlers (monitors). Event-driven programming support can be switched off for specific object using the compiler flag <a title="Consult compiler flag details" href="running.html#options"><code>events</code></a>. Doing so, reduces the number of predicate calls from six to just two.
</p>
<p>
Messages to <em>self</em> and <em>super</em> calls are transparent regarding events and, as such, imply only two predicate calls (the cache lookup and the method call).
</p>
<p>
When a message is sent by the user from the top-level interpreter, Logtalk needs to perform a runtime translation of the message in order to prove the corresponding goal. For user-defined messages/predicates, the runtime translation overhead corresponds to seventeen predicate calls. Thus, while sending a message from a compiled object corresponds to six predicate calls, the same message sent by the user from the top-level interpreter results in twenty-three predicate calls. Considering the time taken for the user to type the goal, this overhead is of no practical consequence.
</p>
<p>
When a message is not cached, the number of predicate calls depends on the number of steps needed for the Logtalk runtime engine to lookup the corresponding predicate scope declaration (to check if the message is valid) and then to lookup a predicate definition for answering the message.
</p>
<h3>Processing time<a name="cputime"></a></h3>
<p>
Not all predicate calls take the same time. Moreover, the time taken to process a specific predicate call depends on the Prolog compiler implementation details. As such, the only valid performance measure is the time taken for processing a message.
</p>
<p>
The usual way of measuring the time taken by a predicate call is to repeat the call a number of times and than to calculate the average time. A sufficient large number of repetitions would hopefully lead to an accurate measure. Care should be taken to subtract the time taken by the repetition code itself. In addition, we should be aware of any limitations of the predicates used to measure execution times. One way to make sense of numbers we get is to repeat the test with the same predicate using plain Prolog and with the predicate encapsulated in a module.
</p>
<p>
A simple predicate for helping benchmarking predicate calls could be:
</p>
<pre>
benchmark(N, Goal) :-
repeat(N),
call(Goal),
fail.
benchmark(_, _).
</pre>
<p>
The rational of using a failure-driven loop is to try to avoid any interference on our timing measurements from garbage-collection or memory expansion mechanisms. Based on the predicate <code>benchmark/2</code>, we may define a more convenient predicate for performing our benchmarks. For example:
</p>
<pre>
benchmark(Goal) :-
N = 10000000, % some sufficiently large number of repetitions
write('Number of repetitions: '), write(N), nl,
get_cpu_time(Seconds1), % replace by your Prolog-specific predicate
benchmark(N, Goal),
get_cpu_time(Seconds2),
Average is (Seconds2 - Seconds1)/N,
write('Average time per call: '), write(Average), write(' seconds'), nl,
Speed is 1.0/Average,
write('Number of calls per second: '), write(Speed), nl.
</pre>
<p>
We can get a baseline for our timings by doing:
</p>
<pre>
| ?- benchmark(true).
</pre>
<p>
For comparing message sending performance across several Prolog compilers, we would call the <code>benchmark/1</code> predicate with a suitable argument. For example:
</p>
<pre>
| ?- benchmark(list::length([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], _)).
</pre>
<p>
For comparing message sending performance with predicate calls in plain Prolog and with calls to predicates encapsulated in modules, we should use exactly the same predicate definition in the three cases.
</p>
<p>
It should be stressed that message sending is only one of the factors affecting the performance of a Logtalk application. The strengths and limitations of the chosen Prolog compiler play a crucial role on all aspects of the development, reliability, usability, and performance of a Logtalk application. It is advisable to take advantage of the Logtalk wide compatibility with most Prolog compilers to test for the best match for developing your Logtalk applications.</p>
<div class="navbottom">
<a href="features.html">previous</a> | <a href="../glossary.html">glossary</a> | <a href="objects.html">next</a>
</div>
<div class="copyright">
Copyright &copy; <a href="mailto:pmoura@logtalk.org">Paulo Moura</a> &mdash; <a href="http://www.logtalk.org">Logtalk.org</a>
</div>
<div class="footer">
<p><span class="bleft"><a href="http://validator.w3.org/check/referer">XHTML</a> + <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a></span><span class="bright">Last updated on: February 6, 2005</span></p>
</div>
</body>
</html>