spirit/classic/phoenix/doc/adaptable_closures.html
Joel de Guzman 994d4e48cc moving stuff to classic spirit
[SVN r44163]
2008-04-10 23:51:31 +00:00

124 lines
11 KiB
HTML

<html>
<head>
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
<title>Adaptable closures</title>
<link rel="stylesheet" href="theme/style.css" type="text/css">
<link rel="prev" href="binders.html">
<link rel="next" href="lazy_construction.html">
</head>
<body>
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
<tr>
<td width="10">
</td>
<td width="85%">
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Adaptable closures</b></font>
</td>
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
</tr>
</table>
<br>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="binders.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="lazy_construction.html"><img src="theme/r_arr.gif" border="0"></a></td>
</tr>
</table>
<p>
The framework will not be complete without some form of closures support. Closures encapsulate a stack frame where local variables are created upon entering a function and destructed upon exiting. Closures provide an environment for local variables to reside. Closures can hold heterogeneous types.</p>
<p>
Phoenix closures are true hardware stack based. Closures enable true reentrancy in lambda functions. A closure provides access to a function stack frame where local variables reside. Modeled after Pascal nested stack frames, closures can be nested just like nested functions where code in inner closures may access local variables from in-scope outer closures (accessing inner scopes from outer scopes is an error and will cause a run-time assertion failure).</p>
<table width="80%" border="0" align="center">
<tr>
<td class="note_box">
<img src="theme/lens.gif"></img> <b>Spirit Closures</b><br><br>
<a href="http://spirit.sourceforge.net">
Spirit</a> uses Phoenix closures to allow parameter passing (inherited and synthetic attributes, in parsing parlance) upstream and downstream in a parse traversal (see <a href="../../index.html">
Spirit</a> documentation). </td>
</tr>
</table>
<p>
There are three (3) interacting classes:</p>
<p>
<b>1) closure:</b></p>
<p>
At the point of declaration, a closure does not yet create a stack frame nor instantiate any variables. A closure declaration declares the types and names of the local variables. The closure class is meant to be subclassed. It is the responsibility of a closure subclass to supply the names for each of the local variable in the closure. Example:</p>
<code><pre>
<span class=keyword>struct </span><span class=identifier>my_closure </span><span class=special>: </span><span class=identifier>closure</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>string</span><span class=special>, </span><span class=keyword>double</span><span class=special>&gt; {
</span><span class=identifier>member1 </span><span class=identifier>num</span><span class=special>; // </span><span class=identifier>names </span><span class=identifier>the </span><span class=number>1</span><span class=identifier>st </span><span class=special>(</span><span class=keyword>int</span><span class=special>) </span><span class=identifier>local </span><span class=identifier>variable
</span><span class=identifier>member2 </span><span class=identifier>message</span><span class=special>; // </span><span class=identifier>names </span><span class=identifier>the </span><span class=number>2</span><span class=identifier>nd </span><span class=special>(</span><span class=identifier>string</span><span class=special>) </span><span class=identifier>local </span><span class=identifier>variable
</span><span class=identifier>member3 </span><span class=identifier>real</span><span class=special>; // </span><span class=identifier>names </span><span class=identifier>the </span><span class=number>3</span><span class=identifier>rd </span><span class=special>(</span><span class=keyword>double</span><span class=special>) </span><span class=identifier>local </span><span class=identifier>variable
</span><span class=special>};
</span><span class=identifier>my_closure </span><span class=identifier>clos</span><span class=special>;
</span></pre></code>
<p>
Now that we have a closure 'clos', its local variables can be accessed lazily using the dot notation. Each qualified local variable can be used just like any primitive actor (see primitives). Examples:</p>
<code><pre>
<span class=identifier>clos</span><span class=special>.</span><span class=identifier>num </span><span class=special>= </span><span class=number>30
</span><span class=identifier>clos</span><span class=special>.</span><span class=identifier>message </span><span class=special>= </span><span class=identifier>arg1
</span><span class=identifier>clos</span><span class=special>.</span><span class=identifier>real </span><span class=special>= </span><span class=identifier>clos</span><span class=special>.</span><span class=identifier>num </span><span class=special>* </span><span class=number>1e6
</span></pre></code>
<p>
The examples above are lazily evaluated. As usual, these expressions return composite actors that will be evaluated through a second function call invocation (see operators). Each of the members (clos.xxx) is an actor. As such, applying the operator() will reveal its identity:</p>
<code><pre>
<span class=identifier>clos</span><span class=special>.</span><span class=identifier>num</span><span class=special>() // </span><span class=identifier>will </span><span class=keyword>return </span><span class=identifier>the </span><span class=identifier>current </span><span class=identifier>value </span><span class=identifier>of </span><span class=identifier>clos</span><span class=special>.</span><span class=identifier>num
</span></pre></code>
<table width="80%" border="0" align="center">
<tr>
<td class="note_box">
<img src="theme/note.gif"></img> <b>Acknowledgement:</b><br><br><b>Juan Carlos Arevalo-Baeza</b> (JCAB) introduced and initilally implemented the closure member names that uses the dot notation and <b>Martin Wille</b> who improved multi thread safety using <a href="http://www.boost.org">
Boost</a> Threads. </td>
</tr>
</table>
<p>
<b>2) closure_member</b></p>
<p>
The named local variables of closure 'clos' above are actually closure members. The closure_member class is an actor and conforms to its conceptual interface. member1..memberN are predefined typedefs that correspond to each of the listed types in the closure template parameters.</p>
<p>
<b>3) closure_frame</b></p>
<p>
When a closure member is finally evaluated, it should refer to an actual instance of the variable in the hardware stack. Without doing so, the process is not complete and the evaluated member will result to an assertion failure. Remember that the closure is just a declaration. The local variables that a closure refers to must still be instantiated.</p>
<p>
The closure_frame class does the actual instantiation of the local variables and links these variables with the closure and all its members. There can be multiple instances of closure_frames typically situated in the stack inside a function. Each closure_frame instance initiates a stack frame with a new set of closure local variables. Example:</p>
<code><pre>
<span class=keyword>void </span><span class=identifier>foo</span><span class=special>()
{
</span><span class=identifier>closure_frame</span><span class=special>&lt;</span><span class=identifier>my_closure</span><span class=special>&gt; </span><span class=identifier>frame</span><span class=special>(</span><span class=identifier>clos</span><span class=special>);
/* </span><span class=keyword>do </span><span class=identifier>something </span><span class=special>*/
}
</span></pre></code>
<p>
where 'clos' is an instance of our closure 'my_closure' above. Take note that the usage above precludes locally declared classes. If my_closure is a locally declared type, we can still use its self_type as a paramater to closure_frame:</p>
<code><pre>
<span class=identifier>closure_frame</span><span class=special>&lt;</span><span class=identifier>my_closure</span><span class=special>::</span><span class=identifier>self_type</span><span class=special>&gt; </span><span class=identifier>frame</span><span class=special>(</span><span class=identifier>clos</span><span class=special>);
</span></pre></code>
<p>
Upon instantiation, the closure_frame links the local variables to the closure. The previous link to another closure_frame instance created before is saved. Upon destruction, the closure_frame unlinks itself from the closure and relinks the preceding closure_frame prior to this instance.</p>
<p>
The local variables in the closure 'clos' above is default constructed in the stack inside function 'foo'. Once 'foo' is exited, all of these local variables are destructed. In some cases, default construction is not desirable and we need to initialize the local closure variables with some values. This can be done by passing in the initializers in a compatible tuple. A compatible tuple is one with the same number of elements as the destination and where each element from the destination can be constructed from each corresponding element in the source. Example:</p>
<code><pre>
<span class=identifier>tuple</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*, </span><span class=keyword>int</span><span class=special>&gt; </span><span class=identifier>init</span><span class=special>(</span><span class=number>123</span><span class=special>, </span><span class=string>&quot;Hello&quot;</span><span class=special>, </span><span class=number>1000</span><span class=special>);
</span><span class=identifier>closure_frame</span><span class=special>&lt;</span><span class=identifier>my_closure</span><span class=special>&gt; </span><span class=identifier>frame</span><span class=special>(</span><span class=identifier>clos</span><span class=special>, </span><span class=identifier>init</span><span class=special>);
</span></pre></code>
<p>
Here now, our closure_frame's variables are initialized with int: 123, char const*: &quot;Hello&quot; and int: 1000.</p>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="binders.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="lazy_construction.html"><img src="theme/r_arr.gif" border="0"></a></td>
</tr>
</table>
<br>
<hr size="1">
<p class="copyright">Copyright &copy; 2001-2002 Joel de Guzman<br>
<br>
<font size="2">Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt) </font> </p>
</body>
</html>