b697f3d34e
git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@1781 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
247 lines
15 KiB
HTML
247 lines
15 KiB
HTML
<?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 user manual: event-driven programming</title>
|
|
<link rel="stylesheet" href="../screen.css" type="text/css" media="screen"/>
|
|
<link rel="stylesheet" href="../print.css" type="text/css" media="print"/>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="top-left">Logtalk user manual</div>
|
|
<div class="top-right">Event-driven programming</div>
|
|
<div class="bottom-left"><span class="page"/></div>
|
|
<div class="bottom-right"><span class="page"/></div>
|
|
<div class="navtop"><a href="../index.html">contents</a> > <a href="index.html">user manual</a></div>
|
|
|
|
<h1>Event-driven programming<span id="events_events"/></h1>
|
|
|
|
<p>
|
|
The addition of event-driven programming capacities to the Logtalk language <a href="../bibliography.html#Moura94">[Moura 94]</a> is based on a simple but powerful idea:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>
|
|
The computations must result, not only from message sending, but also from the <strong>observation</strong> of message sending.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<p>
|
|
The need to associate computations to the occurrence of events was very early recognized in several knowledge representation languages, in some programming languages <a href="../bibliography.html#Stefik86">[Stefik 86</a>, <a href="../bibliography.html#Moon86">Moon 86]</a>, and in the implementation of operative systems <a href="../bibliography.html#Tanenbaum87">[Tanenbaum 87]</a> and graphical user interfaces.
|
|
</p>
|
|
<p>
|
|
With the integration between object-oriented and event-driven programming, we intend to achieve the following goals:
|
|
</p>
|
|
<ul>
|
|
<li>Minimize the coupling between objects. An object should only contain what is intrinsic to it. If an object observes another object, that means that it should depend only on the (public) protocol of the object observed, and not on the implementation of that same protocol.</li>
|
|
</ul>
|
|
<ul>
|
|
<li>Provide a framework for building reflexive systems in Logtalk based on the dynamic behavior of objects in complement to the reflective information of the object's contents and relations.</li>
|
|
</ul>
|
|
|
|
<h2>Definitions<a id="events_definitions"></a></h2>
|
|
|
|
<p>
|
|
The words <em>event</em> and <em>monitor</em> have multiple meanings in computer science, so, to avoid misunderstandings, it is advisable that we start by defining them in the Logtalk context.
|
|
</p>
|
|
|
|
<h3>Event<a id="events_event"></a></h3>
|
|
|
|
<p>
|
|
In an object-oriented system, all computations start through message sending. It thus becomes quite natural to declare that the only event that can occur in this kind of system is precisely the sending of a message. An event can thus be represented by the ordered tuple <code>(Object, Message, Sender)</code>.
|
|
</p>
|
|
<p>
|
|
If we consider message processing an indivisible activity, we can interpret the sending of a message and the return of the control to the object that has sent the message as two distinct events. This distinction allows us to have a more precise control over a system dynamics. In Logtalk, these two types of events have been named <code>before</code> and <code>after</code>, respectively for message sending and returning. Therefore, we end up by representing an event by the ordered tuple <code>(Event, Object, Message, Sender)</code>.
|
|
</p>
|
|
<p>
|
|
The implementation of the event notion in Logtalk enjoys the following properties:
|
|
</p>
|
|
<dl>
|
|
<dt><em>Independence between the two types of events</em></dt>
|
|
<dd>We can choose to watch only one event type or to process each one of the events associated to a message sending in an independent way.</dd>
|
|
<dt><em>All events are automatically generated by the message sending mechanism</em></dt>
|
|
<dd>The task of generating events is accomplished, in a transparent way, by the message sending mechanism. The user just defines which are the events in which he is interested in.</dd>
|
|
<dt><em>The events watched at any moment can be dynamically changed during program execution</em></dt>
|
|
<dd>The notion of event allows the user not only to have the possibility of observing, but also of controlling and modifying an application behavior, namely by dynamically changing the observed events during program execution. It is our goal to provide the user with the possibility of modeling the largest possible number of situations.</dd>
|
|
</dl>
|
|
|
|
<h3>Monitor<a id="events_monitor"></a></h3>
|
|
|
|
<p>
|
|
Complementary to the notion of event is the notion of monitor. A monitor is an object that is automatically notified by the message sending mechanisms whenever certain events occur. A monitor should naturally define the actions to be carried out whenever a monitored event occurs.
|
|
</p>
|
|
<p>
|
|
The implementation of the monitor notion in Logtalk enjoys the following properties:
|
|
</p>
|
|
<dl>
|
|
<dt><em>Any object can act as a monitor</em></dt>
|
|
<dd>The monitor status is a role that any object can perform during its existence. The minimum protocol necessary is declared in the built-in protocol <code>monitoring</code>. Strictly speaking, the reference to this protocol is only needed when specializing event handlers. Nevertheless, it is considered good programming practice to always refer the protocol when defining event handlers.</dd>
|
|
<dt><em>Unlimited number of monitors for each event</em></dt>
|
|
<dd>Several monitors can observe the same event because of distinct reasons. Therefore, the number of monitors per event is bounded only by the available computing resources.</dd>
|
|
<dt><em>The monitor status of an object can be dynamically changed in runtime</em></dt>
|
|
<dd>This property does not imply that an object must be dynamic to act as a monitor (the monitor status of an object is not stored in the object).</dd>
|
|
<dt><em>The execution of actions, defined in a monitor, associated to each event, never affects the term that denotes the message involved</em></dt>
|
|
<dd>In other words, if the message contains uninstantiated variables, these are not affected by the acting of monitors associated to the event.</dd>
|
|
</dl>
|
|
|
|
<h2>Event generation<a id="events_generation"></a></h2>
|
|
|
|
<p>
|
|
For each message that is sent (using the <a title="Consult reference manual" href="../refman/control/to_object2.html"><code>::/2</code></a> message sending mechanism) the runtime system automatically generates two events. The first — <code>before event</code> — is generated when the message is sent. The second — <code>after event</code> — is generated after the message has successfully been executed.
|
|
</p>
|
|
|
|
<h2>Communicating events to monitors<a id="events_communicating"></a></h2>
|
|
|
|
<p>
|
|
Whenever a spied event occurs, the message sending mechanisms call the corresponding event handlers directly for all registered monitors. These calls are made bypassing the message sending primitives in order to avoid potential endless loops. The event handlers consist in user definitions for the public predicates declared in the <code>monitoring</code> built-in protocol (one for each event kind; see below for more details).
|
|
</p>
|
|
|
|
<h2>Performance concerns<a id="events_performance"></a></h2>
|
|
|
|
<p>
|
|
Ideally, the existence of monitored messages should not affect the processing of the remaining messages. On the other hand, for each message that has been sent, the system must verify if its respective event is monitored. Whenever possible, this verification should be performed in constant time and independently from the number of monitored events. The events representation takes advantage of the first argument indexing performed by most Prolog compilers, which ensure — in the general case — an access in constant time.
|
|
</p>
|
|
<p>
|
|
Event-support can be turned off on a per-object (or per-category) basis using the compiler flag <code>events/1</code>. With event-support turned off, Logtalk uses optimized code for processing message sending calls that skips the checking of monitored events, resulting in a small but measurable performance improvement.
|
|
</p>
|
|
|
|
<h2>Monitor semantics<a id="events_semantics"></a></h2>
|
|
|
|
<p>
|
|
The established semantics for monitors actions consists on considering its success as a necessary condition so that a message can succeed:
|
|
</p>
|
|
<ul>
|
|
<li>All actions associated to events of type <code>before</code> must succeed, so that the message processing can start.</li>
|
|
</ul>
|
|
<ul>
|
|
<li>All actions associated to events of type <code>after</code> also have to succeed so that the message itself succeeds. The failure of any action associated to an event of type <code>after</code> forces backtracking over the message execution (the failure of a monitor never causes backtracking over the preceding monitor actions).</li>
|
|
</ul>
|
|
<p>
|
|
Note that this is the most general choice. If we wish a transparent presence of monitors in a message processing, we just have to define the monitor actions in such a way that they never fail (which is very simple to accomplish).
|
|
</p>
|
|
|
|
<h2>Activation order of monitors<a id="events_order"></a></h2>
|
|
|
|
<p>
|
|
Ideally, whenever there are several monitors defined for the same event, the calling order should not interfere with the result. However, this is not always possible. In the case of an event of type <code>before</code>, the failure of a monitor prevents a message from being sent and prevents the execution of the remaining monitors. In case of an event of type <code>after</code>, a monitor failure will force backtracking over message execution. Different orders of monitor activation can therefore lead to different results if the monitor actions imply object modifications unrecoverable in case of backtracking. Therefore, the order for monitor activation must be always taken as arbitrary. In effect, to suppose or to try to impose a specific sequence implies a global knowledge of an application dynamics, which is not always possible. Furthermore, that knowledge can reveal itself as incorrect if there is any changing in the execution conditions. Note that, given the independence between monitors, it does not make sense that a failure forces backtracking over the actions previously executed.
|
|
</p>
|
|
|
|
<h2>Event handling<a id="events_handling"></a></h2>
|
|
|
|
<p>
|
|
Logtalk provides three built-in predicates for event handling. These predicates enable you to find what events are defined, to define new events and to abolish events when they are no longer needed. If you plan to use events extensively in your application, then you should probably define a set of objects that use the built-in predicates described below to implement more sophisticated and high-level behavior.
|
|
</p>
|
|
|
|
<h3>Finding defined events<a id="events_finding"></a></h3>
|
|
|
|
<p>
|
|
The events that are currently defined can be retrieved using the Logtalk built-in predicate <a title="Consult reference manual" href="../refman/builtins/current_event5.html"><code>current_event/5</code></a>:
|
|
</p>
|
|
<pre>| ?- current_event(Event, Object, Message, Sender, Monitor).</pre>
|
|
<p>
|
|
Note that this predicate will return a <strong>set</strong> of matching events if some of the returned arguments are free variables or contain free variables.
|
|
</p>
|
|
|
|
<h3>Defining new events<a id="events_defining"></a></h3>
|
|
|
|
<p>
|
|
New events can be defined using the Logtalk built-in predicate <a title="Consult reference manual" href="../refman/builtins/define_events5.html"><code>define_events/5</code></a>:
|
|
</p>
|
|
<pre>| ?- define_events(Event, Object, Message, Sender, Monitor).</pre>
|
|
<p>
|
|
Note that if any of the arguments is a free variable or contains free variables, this call will define the <strong>set</strong> of matching events.
|
|
</p>
|
|
|
|
<h3>Abolishing defined events<a id="events_abolishing"></a></h3>
|
|
|
|
<p>
|
|
Events that are no longer needed may be abolished using the <a title="Consult reference manual" href="../refman/builtins/abolish_events5.html"><code>abolish_events/5</code></a> built-in predicate:
|
|
</p>
|
|
<pre>| ?- abolish_events(Event, Object, Message, Sender, Monitor).</pre>
|
|
<p>
|
|
If called with free variables, this goal will remove all matching events.
|
|
</p>
|
|
|
|
<h3>Defining event handlers<a id="events_handlers"></a></h3>
|
|
|
|
<p>
|
|
The <code>monitoring</code> built-in protocol declares two public predicates, <a title="Consult reference manual" href="../refman/methods/before3.html"><code>before/3</code></a> and <a title="Consult reference manual" href="../refman/methods/after3.html"><code>after/3</code></a>, that are automatically called to handle <code>before</code> and <code>after</code> events. Any object that plays the role of monitor should define one or both of these event handler methods:
|
|
</p>
|
|
<pre>before(Object, Message, Sender) :-
|
|
... .
|
|
|
|
after(Object, Message, Sender) :-
|
|
... .</pre>
|
|
<p>
|
|
The arguments in both methods are instantiated by the message sending mechanisms when a spied event occurs. For example, assume that we want to define a monitor called <code>tracer</code> that will track any message sent to an object by printing a describing text to the standard output. Its definition could be something like:</p>
|
|
<pre>:- object(tracer,
|
|
implements(monitoring)).
|
|
|
|
before(Object, Message, Sender) :-
|
|
write('call: '), writeq(Object), write(' <-- '), writeq(Message),
|
|
write(' from '), writeq(Sender), nl.
|
|
|
|
after(Object, Message, Sender) :-
|
|
write('exit: '), writeq(Object), write(' <-- '), writeq(Message),
|
|
write(' from '), writeq(Sender), nl.
|
|
|
|
:- end_object.</pre>
|
|
<p>
|
|
Assume that we also have the following object:
|
|
</p>
|
|
<pre>:- object(any).
|
|
|
|
:- public(bar/1) .
|
|
:- public(foo/1) .
|
|
|
|
bar(bar).
|
|
|
|
foo(foo).
|
|
|
|
:- end_object.</pre>
|
|
<p>
|
|
After compiling and loading both objects, we can start tracing every message sent to any object by calling the <code>define_events/5</code> built-in predicate:
|
|
</p>
|
|
<pre>| ?- define_events(_, _, _, _, tracer).
|
|
|
|
yes</pre>
|
|
<p>
|
|
From now on, every message sent to any object will be traced to the standard output stream:
|
|
</p>
|
|
<pre>| ?- any::bar(X).
|
|
|
|
call: any <-- bar(X) from user
|
|
exit: any <-- bar(bar) from user
|
|
X = bar
|
|
|
|
yes</pre>
|
|
<p>
|
|
To stop tracing, we can use the <code>abolish_events/5</code> built-in predicate:
|
|
</p>
|
|
<pre>| ?- abolish_events(_, _, _, _, tracer).
|
|
|
|
yes</pre>
|
|
<p>
|
|
The <code>monitoring</code> protocol declares the event handlers as public predicates. If necessary, protected or private implementation of the protocol may be used in order to change the scope of the event handler predicates. Note that the message sending processing mechanisms are able to call the event handlers irrespective of their scope. Nevertheless, the scope of the event handlers may be restricted in order to prevent other objects from calling them.
|
|
</p>
|
|
|
|
<div class="footer">
|
|
<div class="copyright">
|
|
<span>Copyright © <a href="mailto:pmoura@logtalk.org">Paulo Moura</a> — <a href="http://logtalk.org">Logtalk.org</a></span><br/>
|
|
<span>Last updated on: January 15, 2007</span>
|
|
</div>
|
|
<div class="navbottom">
|
|
<span><a href="inheritance.html">previous</a> | <a href="../glossary.html">glossary</a> | <a href="threads.html">next</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>
|