Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > bd5c3d824c3db63ffd9226c15941e6ad > files > 689

mozart-1.4.0-1mdv2010.0.i586.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>3 Basic Operations and Examples</TITLE><LINK href="ozdoc.css" rel="stylesheet" type="text/css"></HEAD><BODY><TABLE align="center" border="0" cellpadding="6" cellspacing="6" class="nav"><TR bgcolor="#DDDDDD"><TD><A href="node2.html#chapter.distmodel">&lt;&lt; Prev</A></TD><TD><A href="index.html">- Up -</A></TD><TD><A href="node4.html#chapter.failure">Next &gt;&gt;</A></TD></TR></TABLE><DIV id="chapter.examples"><H1><A name="chapter.examples">3 Basic Operations and Examples</A></H1><H2><A name="label158">3.1 Global naming</A></H2><P>There are two kinds of global names in Oz: <A name="label159"></A> </P><UL><LI><P>Internal references, i.e., that can exist only <EM>within</EM> an Oz computation space. They are globally unique, even for references existing before connecting with another application. All data structures in Oz are addressed through these references; they correspond roughly to pointers and network pointers in mainstream languages, but they are protected from abuse (as in Java). See <A href="node2.html#language.entities">Section&nbsp;2.1</A> for more information on the distribution semantics of these references. In most cases, you can ignore these references since they don't affect the language semantics. In this section we will not talk any more of these references. <A name="label160"></A></P></LI><LI><P>External references, i.e., that can exist <EM>anywhere</EM>, i.e., both inside and outside of an Oz computation space. They are also known as external global names. They are represented as character strings, and can therefore be stored and communicated on many different media, including Web pages, Oz computation spaces, etc. They are needed when a Mozart application wants to interact with the external world.</P></LI></UL><P></P><P>This section focuses on external global names. Oz recognizes three kinds, namely tickets, URLs, and hostnames: <A name="label161"></A> <A name="label162"></A> </P><UL><LI><P>A <EM>ticket</EM> is a string that references any language entity inside a running application. Tickets are created within a running Oz application and can be used by active applications to connect together (see module <A href="../system/node47.html#chapter.connection"><CODE>Connection</CODE></A>). <A name="label163"></A> <A name="label164"></A></P></LI><LI><P>A <EM>URL</EM> is a string that references a file across the network. The string follows the standard URL syntax. <A name="label165"></A> <A name="label166"></A> In Mozart the file can be a <EM>pickle</EM>, in which case it can hold any kind of stateless data--procedures, classes, functors, records, strings, and so forth (see module <A href="../system/node57.html#chapter.pickle"><CODE>Pickle</CODE></A>). <A name="label167"></A> <A name="label168"></A></P></LI><LI><P>A <EM>hostname</EM> is a string that refers to a host (another machine) across the network. The string follows the standard DNS syntax. An application can use the hostname to start up a Mozart process on the host (see module <A href="../system/node48.html#chapter.remote"><CODE>Remote</CODE></A>).</P></LI></UL><P></P><P>For maximum flexibility, all three kinds can be represented as virtual strings inside Oz. </P><H3><A name="label169">3.1.1 Connecting applications by means of tickets</A></H3><A name="label170"></A><A name="label171"></A><P>Let's say Application 1 has a stream that it wants others to access. It can do this by creating a ticket that references the stream. Other applications then just need to know the ticket to get access to the stream. Tickets are implemented by the module <A href="../system/node47.html#chapter.connection"><CODE>Connection</CODE></A>, which has the following three operations: </P><UL><LI><P><CODE>{Connection<SPAN class="keyword">.</SPAN>offerOnce&nbsp;X&nbsp;T}</CODE> creates a ticket <CODE>T</CODE> for <CODE>X</CODE>, which can be any language entity. The ticket can be taken just once. Attempting to take a ticket more than once will raise an exception.</P></LI><LI><P><CODE>{Connection<SPAN class="keyword">.</SPAN>offerMany&nbsp;X&nbsp;T}</CODE> creates a ticket <CODE>T</CODE> for <CODE>X</CODE>, which can be any language entity. The ticket can be taken any number of times.</P></LI><LI><P><CODE>{Connection<SPAN class="keyword">.</SPAN>take&nbsp;T&nbsp;X}</CODE> creates a reference <CODE>X</CODE> when given a valid ticket in <CODE>T</CODE>. The <CODE>X</CODE> refers to exactly the same language entity as the original reference that was offered when the ticket was created. A ticket can be taken at any site. If taken at a different site than where the ticket was offered, then there is network communication between the two sites.</P></LI></UL><P></P><P>Application 1 first creates a ticket for the stream as follows: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;Stream&nbsp;Tkt&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>{Connection<SPAN class="keyword">.</SPAN>offerMany&nbsp;Stream&nbsp;Tkt}<BR>{Show&nbsp;Tkt}</CODE></BLOCKQUOTE><P> <A name="label172"></A></P><P>The ticket is returned in <CODE>Tkt</CODE>. Application 1 then publishes the value of <CODE>Tkt</CODE> somewhere so that other applications can access it. Our example uses <CODE>Show</CODE> to display the ticket in the emulator window. We will use copy and paste to communicate the ticket to another application. The ticket looks something like <CODE><SPAN class="string">'oz-ticket://130.104.228.81:9000/h9323679#42'</SPAN></CODE>. Don't worry about exactly what's inside this strange atom. Users don't normally see tickets: they are stored in files or passed across the network, e.g., in mail messages. Application 2 can use the ticket to get a reference to the stream: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;Stream&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>{Connection<SPAN class="keyword">.</SPAN>take&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="string">'oz-ticket://130.104.228.81:9000/h9323679#42'</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;Stream}<BR>{Browse&nbsp;Stream}</CODE></BLOCKQUOTE><P> </P><P>If Application 1 binds the stream by doing <CODE>Stream=a<SPAN class="keyword">|</SPAN>b<SPAN class="keyword">|</SPAN>c<SPAN class="keyword">|</SPAN>_</CODE> then Application 2's browse window will show the bindings. </P><H3><A name="label173">3.1.2 Persistent data structures by means of pickles</A></H3><A name="label174"></A><A name="label175"></A><P>An application can save any stateless data structure in a file and load it again from a file. The loading may also be done from a URL, used as a file's global name. The module <CODE>Pickle</CODE> implements the saving and loading and the conversion between Oz data and a byte sequence. </P><P>For example, let's define a function and save it: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">Fact</SPAN>&nbsp;N}<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">if</SPAN>&nbsp;N<SPAN class="keyword">=&lt;</SPAN>1&nbsp;<SPAN class="keyword">then</SPAN>&nbsp;1&nbsp;<SPAN class="keyword">else</SPAN>&nbsp;N<SPAN class="keyword">*</SPAN>{Fact&nbsp;N<SPAN class="keyword">-</SPAN>1}&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>{Pickle<SPAN class="keyword">.</SPAN>save&nbsp;Fact&nbsp;<SPAN class="string">&quot;~pvr/public_html/fact&quot;</SPAN>}</CODE></BLOCKQUOTE><P> </P><P>Since the function is in a <CODE>public_html</CODE> directory, anyone can load it by giving a URL that specifies the file: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR>Fact={Pickle<SPAN class="keyword">.</SPAN>load&nbsp;<SPAN class="string">&quot;http://www.info.ucl.ac.be/~pvr/fact&quot;</SPAN>}<BR>&nbsp;<BR>{Browse&nbsp;{Fact&nbsp;10}}</CODE></BLOCKQUOTE><P> </P><P>Anything stateless can be saved in a pickle, including functions, procedures, classes, functors, records, and atoms. Stateful entities, such as objects and variables, cannot be pickled. </P><H3><A name="label176">3.1.3 Remote computations and functors</A></H3><A name="label177"></A><A name="label178"></A><A name="label179"></A><P>An application can start a computation on a remote host that uses the resources of that host and that continues to interact with the application. The computation is specified as a <EM>functor</EM>, which is the standard way to define computations with the resources they need. A functor is a module specification that makes explicit the resources that the module needs (see <A href="node2.html#bringing">Section&nbsp;2.3</A>). </P><P>First we create a new Mozart process that is ready to accept new computations: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR>R={New&nbsp;Remote<SPAN class="keyword">.</SPAN>manager&nbsp;init(host:<SPAN class="string">&quot;rainbow.info.ucl.ac.be&quot;</SPAN>)}</CODE></BLOCKQUOTE><P> </P><P>Let's make the process do some work. We define a functor that does the work when we evaluate it: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;F&nbsp;M<BR>F=<SPAN class="keyword">functor</SPAN>&nbsp;<SPAN class="keyword">export</SPAN>&nbsp;x:X&nbsp;<SPAN class="keyword">define</SPAN>&nbsp;X={Fact&nbsp;30}&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;&nbsp;<BR>&nbsp;<BR>M={R&nbsp;apply(F&nbsp;$)}<BR>&nbsp;<BR>{Browse&nbsp;M<SPAN class="keyword">.</SPAN>x}</CODE></BLOCKQUOTE><P> </P><P>The result <CODE>X</CODE> is returned to the client site in the module <CODE>M</CODE>, which is calculated on the remote site and returned to the application site. The module is a record and the result is at the field <CODE>x</CODE>, namely <CODE>M<SPAN class="keyword">.</SPAN>x</CODE>. The module should not reference any resources. If it does, an exception will be raised in the thread doing the <CODE>apply</CODE>. <A name="label180"></A></P><P>Any Oz statement <I>S</I> can be executed remotely by creating a functor: </P><BLOCKQUOTE class="code"><CODE>F=<SPAN class="keyword">functor</SPAN>&nbsp;<SPAN class="keyword">import</SPAN>&nbsp;</CODE><I>ResourceList</I><CODE>&nbsp;<SPAN class="keyword">export</SPAN>&nbsp;</CODE><I>Results</I><CODE>&nbsp;<SPAN class="keyword">define</SPAN>&nbsp;</CODE><I>S</I><CODE>&nbsp;<SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P> To evaluate this functor remotely, the client executes <CODE>M={R&nbsp;apply(F&nbsp;$)}</CODE>. The <I>ResourceList</I> must list all the resources used by <I>S</I>. If not all are listed then an exception will be raised in the thread doing the <CODE>apply</CODE>. The remote execution will use the resources of the remote site and return a module <CODE>M</CODE> that contains all the fields mentioned in <I>Results</I>. If <I>S</I> does not use any resources, then there is a slightly simpler way to do remote computations. The next section shows how by building a simple compute server. </P><P>A second solution is to use a functor with an external reference: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;F&nbsp;M&nbsp;X&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>F=<SPAN class="keyword">functor</SPAN>&nbsp;<SPAN class="keyword">define</SPAN>&nbsp;{Fact&nbsp;30&nbsp;X}&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>M={R&nbsp;apply(F&nbsp;$)}<BR>{Browse&nbsp;X}</CODE></BLOCKQUOTE><P> </P><P>This functor is not stateless, but it's all right since we are not pickling the functor. In fact, it's quite possible for functors to have external references. <A name="label181"></A> <A name="label182"></A> Such functors are called <EM>computed functors</EM>. They can only be pickled if the external references are to stateless entities. </P><P>A third solution is for the functor itself to install the compute server on the remote site. This is a more general solution: it <EM>separates</EM> the distribution aspect (setting up the remote site to do the right thing) from the particular computations that we want to do. We give this solution later in the tutorial. </P><H2><A name="label183">3.2 Servers</A></H2><A name="label184"></A><P>A server is a long-lived computation that provides a service to clients. We will show progressively how to build different kinds of servers. </P><H3><A name="label185">3.2.1 The hello server</A></H3><P>Let's build a basic server that returns the string <CODE><SPAN class="string">&quot;Hello&nbsp;world&quot;</SPAN></CODE> to clients. The first step is to create the server. Let's do this and also make the server available through a URL. </P><BLOCKQUOTE class="code"><CODE>%&nbsp;<SPAN class="comment">Create&nbsp;server<BR></SPAN><SPAN class="keyword">declare</SPAN>&nbsp;Str&nbsp;Prt&nbsp;Srv&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>{NewPort&nbsp;Str&nbsp;Prt}<BR><SPAN class="keyword">thread</SPAN>&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;{ForAll&nbsp;Str&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;S}&nbsp;S=<SPAN class="string">&quot;Hello&nbsp;world&quot;</SPAN>&nbsp;<SPAN class="keyword">end</SPAN>}<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">Srv</SPAN>&nbsp;X}<BR>&nbsp;&nbsp;&nbsp;{Send&nbsp;Prt&nbsp;X}<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>%&nbsp;<SPAN class="comment">Make&nbsp;server&nbsp;available&nbsp;through&nbsp;a&nbsp;URL:<BR></SPAN>%&nbsp;<SPAN class="comment">(by&nbsp;using&nbsp;a&nbsp;filename&nbsp;that&nbsp;is&nbsp;also&nbsp;accessible&nbsp;by&nbsp;URL)<BR></SPAN>{Pickle<SPAN class="keyword">.</SPAN>save&nbsp;{Connection<SPAN class="keyword">.</SPAN>offerMany&nbsp;Srv}&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="string">&quot;/usr/staff/pvr/public_html/hw&quot;</SPAN>}</CODE></BLOCKQUOTE><P></P><P>All the above must be executed on the server site. Later on we will show how a client can create a server remotely. </P><P>Any client that knows the URL can access the server: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;Srv&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>Srv={Connection<SPAN class="keyword">.</SPAN>take&nbsp;{Pickle<SPAN class="keyword">.</SPAN>load&nbsp;<SPAN class="string">&quot;http://www.info.ucl.ac.be/~pvr/hw&quot;</SPAN>}}<BR>&nbsp;<BR><SPAN class="keyword">local</SPAN>&nbsp;X&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;{Srv&nbsp;X}<BR>&nbsp;&nbsp;&nbsp;{Browse&nbsp;X}<BR><SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P></P><P>This will show <CODE><SPAN class="string">&quot;Hello&nbsp;world&quot;</SPAN></CODE> in the browser window. </P><P>By taking the connection, the client gets a reference to the server. This conceptually merges the client and server computation spaces into a single computation space. The client and server can then communicate as if they were in the same process. Later on, when the client forgets the server reference, the computation spaces become separate again. </P><H3><A name="label186">3.2.2 The hello server with stationary objects</A></H3><A name="label187"></A><P>The previous section shows how to build a basic server using a port to collect messages. There is in fact a much simpler way, namely by using stationary objects. Here's how to create the server: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">HelloWorld</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">meth</SPAN>&nbsp;<SPAN class="functionname">hw</SPAN>(X)&nbsp;X=<SPAN class="string">&quot;Hello&nbsp;world&quot;</SPAN>&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>Srv={NewStat&nbsp;HelloWorld&nbsp;hw(_)}&nbsp;%&nbsp;<SPAN class="comment">Requires&nbsp;an&nbsp;initial&nbsp;method</SPAN></CODE></BLOCKQUOTE><P></P><P>The client calls the server as <CODE>{Srv&nbsp;hw(X)}</CODE>. The class <CODE>HelloWorld</CODE> can be replaced by any class. The only difference between this and creating a centralized object is that <CODE>New</CODE> is replaced by <CODE>NewStat</CODE>. This specifies the distributed semantics of the object independently of the object's class. </P><DIV id="making.stationary.objects"><H3><A name="making.stationary.objects">3.2.3 Making stationary objects</A></H3><A name="label188"></A><A name="label189"></A><P>Stationary entities are a very important abstraction. Mozart provides two operations to make entities stationary. The first is creating a stationary object: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR>Object={NewStat&nbsp;Class&nbsp;Init}</CODE></BLOCKQUOTE><P></P><P>When executed on a site, the procedure <CODE>NewStat</CODE> takes a class and an initial message and creates an object that is stationary on that site. We define <CODE>NewStat</CODE> as follows. </P><DL><DT><SPAN class="chunktitle"><SPAN class="chunkborder">&lt;</SPAN><A name="label190">Stationary object</A><SPAN class="chunkborder">&gt;=</SPAN></SPAN></DT><DD class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR></CODE><SPAN class="chunktitle"><SPAN class="chunkborder">&lt;</SPAN><A href="node3.html#label191">MakeStat definition</A><SPAN class="chunkborder">&gt;</SPAN></SPAN><CODE>&nbsp;<BR>&nbsp;<BR><SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">NewStat</SPAN>&nbsp;Class&nbsp;Init&nbsp;Object}<BR>&nbsp;&nbsp;&nbsp;Object={MakeStat&nbsp;{New&nbsp;Class&nbsp;Init}}<BR><SPAN class="keyword">end</SPAN></CODE></DD></DL><P> </P><P><CODE>NewStat</CODE> is defined in terms of <CODE>MakeStat</CODE>. The procedure <CODE>MakeStat</CODE> takes an object or a one-argument procedure and returns a one-argument procedure that obeys exactly the same language semantics and is stationary. We define <CODE>{MakeStat&nbsp;PO&nbsp;StatP}</CODE> as follows, where input <CODE>PO</CODE> is an object or a one-argument procedure and output <CODE>StatP</CODE> is a one-argument procedure. <A href="node3.html#label206"><SUP>1</SUP></A> </P><DL><DT><SPAN class="chunktitle"><SPAN class="chunkborder">&lt;</SPAN><A name="label191">MakeStat definition</A><SPAN class="chunkborder">&gt;=</SPAN></SPAN></DT><DD class="code"><CODE><SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">MakeStat</SPAN>&nbsp;PO&nbsp;?StatP}<BR>&nbsp;&nbsp;&nbsp;S&nbsp;P={NewPort&nbsp;S}<BR>&nbsp;&nbsp;&nbsp;N={NewName}<BR><SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">Client&nbsp;side:<BR></SPAN>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">StatP</SPAN>&nbsp;M}<BR>&nbsp;&nbsp;&nbsp;R&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Send&nbsp;P&nbsp;M<SPAN class="keyword">#</SPAN>R}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">if</SPAN>&nbsp;R<SPAN class="keyword">==</SPAN>N&nbsp;<SPAN class="keyword">then</SPAN>&nbsp;<SPAN class="keyword">skip</SPAN>&nbsp;<SPAN class="keyword">else</SPAN>&nbsp;<SPAN class="keyword">raise</SPAN>&nbsp;R&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">Server&nbsp;side:<BR></SPAN>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">thread</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ForAll&nbsp;S<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;M<SPAN class="keyword">#</SPAN>R}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">thread</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">try</SPAN>&nbsp;{PO&nbsp;M}&nbsp;R=N&nbsp;<SPAN class="keyword">catch</SPAN>&nbsp;X&nbsp;<SPAN class="keyword">then</SPAN>&nbsp;R=X&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>}<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">end</SPAN></CODE></DD></DL><P> </P><P><CODE>StatP</CODE> preserves exactly the same language semantics as <CODE>PO</CODE>. In particular, it has the same concurrency behavior and it raises the same exceptions. The new name <CODE>N</CODE> is a globally-unique token. This ensures that there is no conflict with any exceptions raised by <CODE>ProcOrObj</CODE>. </P></DIV><DIV id="making.objects.stationary"><H3><A name="making.objects.stationary">3.2.4 Making stationary objects, the new way</A></H3><P>Since version 1.4.0, Mozart has built-in support to make objects stationary. The platform provides a way for the programmer to <EM>choose a different protocol</EM> for objects, or any entity in general. By default, object-records are copied lazily, and object states are mobile. But we can enforce the platform to use the so-called <EM>stationary protocol</EM> for a given object. <A name="label192"></A> This is done by <EM>annotating</EM> the object: the annotation specifies a desired distributed behavior for the object. </P><P>An entity is annotated with the procedure <A name="label193"></A> <A name="label194"></A> <CODE>DP<SPAN class="keyword">.</SPAN>annotate</CODE>. The procedure takes the entity and an <EM>annotation</EM>, and attaches the annotation to the entity. The annotation is an atom or a list of atoms. It will be used by the distribution subsystem once the entity becomes distributed. Note that it is important to annotate the entity <EM>before</EM> it gets distributed. The protocol used by an entity cannot be changed once it is distributed. </P><P>In the following example, the object is created with the procedure <CODE>New</CODE>. It it then annotated with the atom <CODE>stationary</CODE>, which is tells Mozart to use the stationary protocol instead of the default one. The distributed behavior of the object is exactly as expected. </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">HelloWorld</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">meth</SPAN>&nbsp;<SPAN class="functionname">hw</SPAN>(X)&nbsp;X=<SPAN class="string">&quot;Hello&nbsp;world&quot;</SPAN>&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>Srv={New&nbsp;HelloWorld&nbsp;hw(_)}<BR>{DP<SPAN class="keyword">.</SPAN>annotate&nbsp;Srv&nbsp;stationary}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">make&nbsp;Srv&nbsp;stationary</SPAN></CODE></BLOCKQUOTE><P> </P><P>We now have an alternative definition for <CODE>NewStat</CODE>, using annotations: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">NewStat</SPAN>&nbsp;Class&nbsp;Init}<BR>&nbsp;&nbsp;&nbsp;Obj={New&nbsp;Class&nbsp;Init}<BR><SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;{DP<SPAN class="keyword">.</SPAN>annotate&nbsp;Obj&nbsp;stationary}<BR>&nbsp;&nbsp;&nbsp;Obj<BR><SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P> </P></DIV><DIV id="compute.server"><H3><A name="compute.server">3.2.5 A compute server</A></H3><A name="label195"></A><A name="label196"></A><P>One of the promises of distributed computing is making computations go faster by exploiting the parallelism inherent in networks of computers. A first step is to create a compute server, that is, a server that accepts any computation and uses its computational resources to do the computation. Here's one way to create a compute server: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">ComputeServer</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">meth</SPAN>&nbsp;<SPAN class="functionname">init</SPAN>&nbsp;<SPAN class="keyword">skip</SPAN>&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">meth</SPAN>&nbsp;<SPAN class="functionname">run</SPAN>(P)&nbsp;{P}&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>C={NewStat&nbsp;ComputeServer&nbsp;init}</CODE></BLOCKQUOTE><P></P><P>The compute server can be made available through a URL as shown before. Here's how a client uses the compute server: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">Fibo</SPAN>&nbsp;N}<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">if</SPAN>&nbsp;N<SPAN class="keyword">&lt;</SPAN>2&nbsp;<SPAN class="keyword">then</SPAN>&nbsp;1&nbsp;<SPAN class="keyword">else</SPAN>&nbsp;{Fibo&nbsp;N<SPAN class="keyword">-</SPAN>1}<SPAN class="keyword">+</SPAN>{Fibo&nbsp;N<SPAN class="keyword">-</SPAN>2}&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>%&nbsp;<SPAN class="comment">Do&nbsp;first&nbsp;computation&nbsp;remotely<BR></SPAN><SPAN class="keyword">local</SPAN>&nbsp;F&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;{C&nbsp;run(<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>}&nbsp;F={Fibo&nbsp;30}&nbsp;<SPAN class="keyword">end</SPAN>)}<BR>&nbsp;&nbsp;&nbsp;{Browse&nbsp;F}<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>%&nbsp;<SPAN class="comment">Do&nbsp;second&nbsp;computation&nbsp;locally<BR></SPAN><SPAN class="keyword">local</SPAN>&nbsp;F&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;F={Fibo&nbsp;30}<BR>&nbsp;&nbsp;&nbsp;{Browse&nbsp;F}<BR><SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P></P><P>This first does the computation remotely and then repeats it locally. In the remote case, the variable <CODE>F</CODE> is shared between the client and server. When the server binds it, its value is immediately sent to the server. This is how the client gets a result from the server. <A name="label197"></A></P><P>Any Oz statement <EM>S</EM> that does not use resources can be executed remotely by making a procedure out of it: </P><BLOCKQUOTE class="code"><CODE>P=<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>}&nbsp;</CODE><I>S</I><CODE>&nbsp;<SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P> To run this, the client just executes <CODE>{C&nbsp;run(P)}</CODE>. Because Mozart is fully network-transparent, <I>S</I> can be any statement in the language: for example, <I>S</I> can define new classes inheriting from client classes. If <I>S</I> uses resources, then it can be executed remotely by means of functors. This is shown in the previous section. </P></DIV><H3><A name="label198">3.2.6 A compute server with functors</A></H3><P>The solution of the previous section is reasonable when the client and server are independent computations that connect. Let's now see how the client itself can start up a compute server on a remote site. The client first creates a new Mozart process: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR>R={New&nbsp;Remote<SPAN class="keyword">.</SPAN>manager&nbsp;init(host:<SPAN class="string">&quot;rainbow.info.ucl.ac.be&quot;</SPAN>)}</CODE></BLOCKQUOTE><P> </P><P>Then the client sends a functor to this process that, when evaluated, creates a compute server: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;F&nbsp;C<BR>F=<SPAN class="keyword">functor</SPAN>&nbsp;&nbsp;<BR>&nbsp;&nbsp;<SPAN class="keyword">export</SPAN>&nbsp;cs:CS<BR>&nbsp;&nbsp;<SPAN class="keyword">define</SPAN>&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">ComputeServer</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">meth</SPAN>&nbsp;<SPAN class="functionname">init</SPAN>&nbsp;<SPAN class="keyword">skip</SPAN>&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">meth</SPAN>&nbsp;<SPAN class="functionname">run</SPAN>(P)&nbsp;{P}&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CS={NewStat&nbsp;ComputeServer&nbsp;init}<BR>&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>C={R&nbsp;apply(F&nbsp;$)}<SPAN class="keyword">.</SPAN>cs&nbsp;&nbsp;%&nbsp;<SPAN class="comment">Set&nbsp;up&nbsp;the&nbsp;compute&nbsp;server</SPAN></CODE></BLOCKQUOTE><P> </P><P>The client can use the compute server as before: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">local</SPAN>&nbsp;F&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;{C&nbsp;run(<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>}&nbsp;F={Fibo&nbsp;30}&nbsp;<SPAN class="keyword">end</SPAN>)}<BR>&nbsp;&nbsp;&nbsp;{Browse&nbsp;F}<BR><SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P> </P><H3><A name="label199">3.2.7 A dynamically-extensible server</A></H3><A name="label200"></A><P>Sometimes a server has to be upgraded, for example to add extra functionality or to fix a bug. We show how to upgrade a server without stopping it. <A name="label201"></A> This cannot be done in Java. In Mozart, the upgrade can even be done interactively. A person sits down at a terminal anywhere in the world, starts up an interactive Mozart session, and upgrades the server while it is running. </P><P>Let's first define a generic upgradable server: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">NewUpgradableStat</SPAN>&nbsp;Class&nbsp;Init&nbsp;?Upg&nbsp;?Srv}<BR>&nbsp;&nbsp;&nbsp;Obj={New&nbsp;Class&nbsp;Init}<BR>&nbsp;&nbsp;&nbsp;C={NewCell&nbsp;Obj}<BR><SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;Srv={MakeStat&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;M}&nbsp;{<SPAN class="keyword">@</SPAN>C&nbsp;M}&nbsp;<SPAN class="keyword">end</SPAN>}<BR>&nbsp;&nbsp;&nbsp;Upg={MakeStat<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;Class2<SPAN class="keyword">#</SPAN>Init2}&nbsp;C&nbsp;<SPAN class="keyword">:=</SPAN>&nbsp;{New&nbsp;Class2&nbsp;Init2}&nbsp;<SPAN class="keyword">end</SPAN>}<BR><SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P></P><P>This definition must be executed on the server site. It returns a server <CODE>Srv</CODE> and a stationary procedure <CODE>Upg</CODE> used for upgrading the server. The server is upgradable because it does all object calls indirectly through the cell <CODE>C</CODE>. </P><P>A client creates an upgradable compute server almost exactly as it creates a fixed compute server, by executing the following on the server site: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;Srv&nbsp;Upg&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>Srv={NewUpgradableStat&nbsp;ComputeServer&nbsp;init&nbsp;Upg}</CODE></BLOCKQUOTE><P></P><P>Let's now upgrade the compute server while it is running. We first define a new class <CODE>CComputeServer</CODE> and then we upgrade the server with an object of the new class: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">CComputeServer</SPAN>&nbsp;<SPAN class="keyword">from</SPAN><SPAN class="type">&nbsp;ComputeServer</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">meth</SPAN>&nbsp;<SPAN class="functionname">run</SPAN>(P&nbsp;Prio<SPAN class="keyword">&lt;=</SPAN>medium)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">thread</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Thread<SPAN class="keyword">.</SPAN>setThisPriority&nbsp;Prio}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ComputeServer<SPAN class="keyword">,</SPAN>run(P)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;<BR>Srv2={Upg&nbsp;CComputeServer<SPAN class="keyword">#</SPAN>init}</CODE></BLOCKQUOTE><P> </P><P>That's all there is to it. The upgraded compute server overrides the <CODE>run</CODE> method with a new method that has a default. The new method supports the original call <CODE>run(P)</CODE> and adds a new call <CODE>run(P&nbsp;Prio)</CODE>, where <CODE>Prio</CODE> sets the priority of the thread doing computation <CODE>P</CODE>. <A name="label202"></A></P><P>The compute server can be upgraded indefinitely since garbage collection will remove any unused old compute server code. For example, it would be nice if the client could find out how many active computations there are on the compute server before deciding whether or not to do a computation there. We leave it to the reader to upgrade the server to add a new method that returns the number of active computations at each priority level. </P><DIV id="practical.tips"><H2><A name="practical.tips">3.3 Practical tips</A></H2><P>This section gives some practical programming tips to improve the network performance of distributed applications: timing and memory problems, avoiding sending data that is not used at the destination and avoiding sending classes when sending objects across the network. </P><H3><A name="label203">3.3.1 Timing and memory problems</A></H3><P>When the distribution structure of an application is changed, then one must be careful not to cause timing and memory problems. </P><UL><LI><P>When a reference <CODE>X</CODE> is exported from a site (i.e., put in a message and sent) and <CODE>X</CODE> refers directly or indirectly to unused modules then the modules will be loaded into memory. This is so even if they will never be used. </P></LI><LI><P>Relative timings between different parts of a program depend on the distribution structure. For example, unsynchronized producer/consumer threads may work fine if both are on the same site: it suffices to give the producer thread a slightly lower priority. If the threads are on different sites, the producer may run faster and cause a memory leak. </P></LI><LI><P>If the same record is sent repeatedly to a site, then a new copy of the record will be created there each time. This is true because records don't have global names. The lack of global names makes it faster to send records across the network.</P></LI></UL><P> </P><H3><A name="label204">3.3.2 Avoiding sending useless data</A></H3><P>When sending a procedure over the network, be sure that it doesn't contain calculations that could have been done on the original site. For example, the following code sends the procedure <CODE>P</CODE> to remote object <CODE>D</CODE>: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR>R={MakeTuple&nbsp;big&nbsp;100000}&nbsp;&nbsp;%&nbsp;<SPAN class="comment">A&nbsp;very,&nbsp;very&nbsp;big&nbsp;tuple<BR></SPAN><SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">P</SPAN>&nbsp;X}&nbsp;X=R<SPAN class="keyword">.</SPAN>2710&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">Procedure&nbsp;that&nbsp;uses&nbsp;tuple&nbsp;field&nbsp;2710<BR></SPAN>{D&nbsp;addentry(P)}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">Send&nbsp;P&nbsp;to&nbsp;D,&nbsp;where&nbsp;it&nbsp;is&nbsp;executed</SPAN></CODE></BLOCKQUOTE><P></P><P>If <CODE>D</CODE> executes <CODE>P</CODE>, then the big tuple <CODE>R</CODE> is transferred to <CODE>D</CODE>'s site, where field number <CODE>2710</CODE> is extracted. With 100,000 fields, this means 400KB is sent over the network! Much better is to extract the field before sending <CODE>P</CODE>: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR>R={MakeTuple&nbsp;big&nbsp;100000}<BR>F=R<SPAN class="keyword">.</SPAN>2710&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">Extract&nbsp;field&nbsp;2710&nbsp;before&nbsp;sending<BR></SPAN><SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">P</SPAN>&nbsp;X}&nbsp;X=F&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>{D&nbsp;addentry(P)}</CODE></BLOCKQUOTE><P></P><P>This avoids sending the tuple across the network. This technique is a kind of partial evaluation. It is useful for almost any Oz entity, for example procedures, functions, classes, and functors. </P><H3><A name="label205">3.3.3 Avoiding sending classes</A></H3><P>When sending an object across the network, it is good to make sure that the object's class exists at the destination site. This avoids sending the class code across the network. Let's see how this works in the case of a collaborative tool. Two sites have identical binaries of this tool, which they are running. The two sites send objects back and forth. Here's how to write the application: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">declare</SPAN>&nbsp;<BR><SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">C</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">...&nbsp;lots&nbsp;of&nbsp;class&nbsp;code&nbsp;comes&nbsp;here<BR></SPAN><SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">functor</SPAN>&nbsp;<BR><SPAN class="keyword">define</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;Obj={New&nbsp;C&nbsp;init}<BR>&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">...&nbsp;code&nbsp;for&nbsp;the&nbsp;collaborative&nbsp;tool<BR></SPAN><SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P></P><P>This creates the class <CODE>C</CODE> for the functor to reference. This means that all copies of the binary with this functor will reference the <EM>same</EM> class, so that an object arriving at a site will recognize the <EM>same</EM> class as its class on the original site. </P><P>Here's how <EM>not</EM> to write the application: </P><BLOCKQUOTE class="code"><CODE><SPAN class="keyword">functor</SPAN>&nbsp;<BR><SPAN class="keyword">define</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">C</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">...&nbsp;lots&nbsp;of&nbsp;class&nbsp;code&nbsp;comes&nbsp;here<BR></SPAN>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;Obj={New&nbsp;C&nbsp;init}<BR>&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">...&nbsp;code&nbsp;for&nbsp;the&nbsp;collaborative&nbsp;tool<BR></SPAN><SPAN class="keyword">end</SPAN></CODE></BLOCKQUOTE><P></P><P>Do you see why? Think first before reading the next paragraph! For a hint read <A href="node2.html#stateless.entities">Section&nbsp;2.1.4</A>. </P><P>In both solutions, the functor is applied when the application starts up. In the second solution, this defines a new and different class <CODE>C</CODE> on each site. If an object of class <CODE>C</CODE> is passed to a site, then the site will ask for the class code to be passed too. This can be very slow if the class is big--for TransDraw it makes a difference of several minutes on a typical Internet connection. In the first solution, the class <CODE>C</CODE> is defined <EM>before</EM> the functor is applied. When the functor is applied, the class already exists! This means that all sites have exactly the same class, which is part of the binary on each site. Objects passed between the sites will never cause class code to be sent. </P></DIV></DIV><TABLE align="center" border="0" cellpadding="6" cellspacing="6" class="nav"><TR bgcolor="#DDDDDD"><TD><A href="node2.html#chapter.distmodel">&lt;&lt; Prev</A></TD><TD><A href="index.html">- Up -</A></TD><TD><A href="node4.html#chapter.failure">Next &gt;&gt;</A></TD></TR></TABLE><HR align="left" width="30%"><DIV class="footnote"><A name="label206">1. </A>One-argument procedures are not exactly objects, since they do not have features. For all practical purposes not requiring features, though, one-argument procedures and objects are interchangeable.</DIV><HR><ADDRESS><A href="http://www.info.ucl.ac.be/~pvr">Peter&nbsp;Van Roy</A>, <A href="http://www.sics.se/~seif">Seif&nbsp;Haridi</A>, <A href="http://www.sics.se/~perbrand">Per&nbsp;Brand</A> and&nbsp;<A href="http://www.info.ucl.ac.be/~raph">Raphael&nbsp;Collet</A><BR><SPAN class="version">Version 1.4.0 (20090610)</SPAN></ADDRESS></BODY></HTML>