here - Stefan-Marr.de
here - Stefan-Marr.de
here - Stefan-Marr.de
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
5.3. The OMOP By Example<br />
The process that has been spawned during the initialization of the agent object<br />
tries in<strong>de</strong>finitely to process these update blocks in #processUpdateBlock.<br />
It waits for the next update block, evaluates it with the current state as argument,<br />
and sets the result value as new state.<br />
This implementation is simplified but represents the essence of Clojure<br />
agents. The differences with the Clojure implementation sketched in Sec. 2.4.3<br />
originate from language differences between SOM and Clojure. For instance,<br />
SOM does not have the notion of private methods, which leaves the implementation<br />
methods #initialize and #processUpdateBlock exposed to arbitrary<br />
use. Thus, these methods could be called from another thread and violate<br />
the assumption that only one update function is executed at a time. The remaining<br />
differences originate from the use of the OMOP. Note that the #read,<br />
#initialize, and #send: method are annotated with unenforced. They are<br />
by themselves not subject to the OMOP’s enforcement, guaranteeing that it<br />
does not come to meta recursion during their execution.<br />
Providing exten<strong>de</strong>d Guarantees based on the OMOP While Clojure gui<strong>de</strong>s<br />
<strong>de</strong>velopers to use agents in conjunction with immutable data structures, at the<br />
same time it makes the pragmatic <strong>de</strong>cision not to enforce any such guarantees<br />
on top of the JVM. One reason for this is the anticipated performance impact.<br />
Another issue is the integration with Java itself, which makes it impossible<br />
to provi<strong>de</strong> such guarantees consistently. This section uses this example to<br />
<strong>de</strong>monstrate how the OMOP can be used to express and in return enforce<br />
such guarantees concisely.<br />
To this end, Lst. 5.3 <strong>de</strong>fines the AgentDomain. The domain implements the<br />
intercession handler #requestExecOf:on:with: to ensure that only a single<br />
thread of execution modifies the agent and that the agent is not reinitialized.<br />
In this simple example, this is done by using a list of selectors that are allowed<br />
to be executed. In case any other selector is sent to an agent, an error is raised<br />
to report the violation. 5<br />
As the ImmutableDomain in Sec. 5.3.1 shows, adding the guarantee of immutability<br />
is also possible in a concise manner. Using the ImmutableDomain<br />
of Lst. 5.1 in this example, the agent ensures in #processUpdateBlock that the<br />
state is an immutable object. This is done by requiring the immutable domain<br />
to #adopt: the return value of an update block. 6<br />
5 Our actual implementation of agents goes beyond what is presented <strong>here</strong>. For brevity, the<br />
example leaves out operations such as #await and #send:with:.<br />
6 In the current implementation #adopt: performs a shallow adopt only and thus, only the<br />
root object of the object graph is ma<strong>de</strong> immutable.<br />
123