63 lines
30 KiB
HTML
63 lines
30 KiB
HTML
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
|
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><meta name="viewport" content="width=device-width, initial-scale=0.8"/><title>6.12 Surrogates</title><link rel="stylesheet" type="text/css" href="../scribble.css" title="default"/><link rel="stylesheet" type="text/css" href="extras.css" title="default"/><link rel="stylesheet" type="text/css" href="../racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../doc-site.css" title="default"/><script type="text/javascript" src="../scribble-common.js"></script><script type="text/javascript" src="../manual-racket.js"></script><script type="text/javascript" src="../manual-racket.js"></script><script type="text/javascript" src="../doc-site.js"></script><script type="text/javascript" src="../local-redirect/local-redirect.js"></script><script type="text/javascript" src="../local-redirect/local-user-redirect.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="doc-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">►</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">The Racket Reference</a></td></tr></table></div><div class="tocviewsublisttop" style="display: none;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="model.html" class="tocviewlink" data-pltdoc="x">Language Model</a></td></tr><tr><td align="right">2 </td><td><a href="notation.html" class="tocviewlink" data-pltdoc="x">Notation for Documentation</a></td></tr><tr><td align="right">3 </td><td><a href="syntax.html" class="tocviewlink" data-pltdoc="x">Syntactic Forms</a></td></tr><tr><td align="right">4 </td><td><a href="data.html" class="tocviewlink" data-pltdoc="x">Datatypes</a></td></tr><tr><td align="right">5 </td><td><a href="structures.html" class="tocviewlink" data-pltdoc="x">Structures</a></td></tr><tr><td align="right">6 </td><td><a href="mzlib_class.html" class="tocviewselflink" data-pltdoc="x">Classes and Objects</a></td></tr><tr><td align="right">7 </td><td><a href="mzlib_unit.html" class="tocviewlink" data-pltdoc="x">Units</a></td></tr><tr><td align="right">8 </td><td><a href="contracts.html" class="tocviewlink" data-pltdoc="x">Contracts</a></td></tr><tr><td align="right">9 </td><td><a href="match.html" class="tocviewlink" data-pltdoc="x">Pattern Matching</a></td></tr><tr><td align="right">10 </td><td><a href="control.html" class="tocviewlink" data-pltdoc="x">Control Flow</a></td></tr><tr><td align="right">11 </td><td><a href="concurrency.html" class="tocviewlink" data-pltdoc="x">Concurrency and Parallelism</a></td></tr><tr><td align="right">12 </td><td><a href="Macros.html" class="tocviewlink" data-pltdoc="x">Macros</a></td></tr><tr><td align="right">13 </td><td><a href="input-and-output.html" class="tocviewlink" data-pltdoc="x">Input and Output</a></td></tr><tr><td align="right">14 </td><td><a href="security.html" class="tocviewlink" data-pltdoc="x">Reflection and Security</a></td></tr><tr><td align="right">15 </td><td><a href="os.html" class="tocviewlink" data-pltdoc="x">Operating System</a></td></tr><tr><td align="right">16 </td><td><a href="memory.html" class="tocviewlink" data-pltdoc="x">Memory Management</a></td></tr><tr><td align="right">17 </td><td><a href="unsafe.html" class="tocviewlink" data-pltdoc="x">Unsafe Operations</a></td></tr><tr><td align="right">18 </td><td><a href="running.html" class="tocvie
|
||
|
for building an instance of the <a name="(tech._proxy._design._pattern)"></a><span style="font-style: italic">proxy design pattern</span>. The
|
||
|
pattern consists of two objects, a <span style="font-style: italic">host</span> and a
|
||
|
<span style="font-style: italic">surrogate</span> object. The host object delegates method calls to
|
||
|
its surrogate object. Each host has a dynamically assigned surrogate,
|
||
|
so an object can completely change its behavior merely by changing the
|
||
|
surrogate.</p><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" cellpadding="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>syntax</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(form._((lib._racket/surrogate..rkt)._surrogate))"></a><span title="Provided from: racket/surrogate | Package: base"><span class="RktSym"><a href="Surrogates.html#%28form._%28%28lib._racket%2Fsurrogate..rkt%29._surrogate%29%29" class="RktStxDef RktStxLink" data-pltdoc="x">surrogate</a></span></span><span class="hspace"> </span><span class="RktVar">use-wrapper-proc</span><span class="hspace"> </span><span class="RktVar">method-spec</span><span class="hspace"> </span><span class="RktMeta">...</span><span class="RktPn">)</span></p></blockquote></td></tr><tr><td><span class="stt"> </span></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="specgrammar"><tr><td align="right" valign="baseline"><span class="RktVar">use-wrapper-proc</span></td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="center" valign="baseline">=</td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="RktPn">#:use-wrapper-proc</span></td></tr><tr><td align="right" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="center" valign="baseline">|</td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td></td></tr></table></td></tr><tr><td align="right" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="center" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="stt"> </span></td></tr><tr><td align="right" valign="baseline"><span class="RktVar">method-spec</span></td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="center" valign="baseline">=</td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="RktPn">(</span><span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._augment%29%29" class="RktStxLink" data-pltdoc="x">augment</a></span><span class="hspace"> </span><span class="RktVar">default-expr</span><span class="hspace"> </span><span class="RktVar">method-id</span><span class="hspace"> </span><span class="RktVar">arg-spec</span><span class="hspace"> </span><span class="RktMeta">...</span><span class="RktPn">)</span></td></tr><tr><td align="right" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="center" valign="baseline">|</td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="RktPn">(</span><span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._override%29%29" class="RktStxLink" data-pltdoc="x">override</a></span><span class="hspace"> </span><span class="RktVar">method-id</span><span class="hspace"> </span><span class="RktVar">arg-spec</span><span class="hspace"> </span><span class="RktMeta">...</span><span class="RktPn">)</span></td></tr><tr><td align="right" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="center" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="stt"> </span></td><td align="left" valign="baseline"><span class="stt"> </span></td></tr><tr><td align="r
|
||
|
procedure that accepts and returns a class), a host <a href="mzlib_class.html#%28tech._interface%29" class="techoutside" data-pltdoc="x"><span class="techinside">interface</span></a>, a
|
||
|
surrogate <a href="mzlib_class.html#%28tech._clas%29" class="techoutside" data-pltdoc="x"><span class="techinside">class</span></a>, and a surrogate <a href="mzlib_class.html#%28tech._interface%29" class="techoutside" data-pltdoc="x"><span class="techinside">interface</span></a>.</div></p><p>If <span class="RktPn">#:use-wrapper-proc</span> does not appear,
|
||
|
the host mixin adds a single private field to its argument. It also adds getter and setter methods
|
||
|
<span class="RktSym">get-surrogate</span> and <span class="RktSym">set-surrogate</span> to get and set the value of the field. The
|
||
|
<span class="RktSym">set-surrogate</span> method accepts instances of the class returned by
|
||
|
the <span class="RktSym"><a href="Surrogates.html#%28form._%28%28lib._racket%2Fsurrogate..rkt%29._surrogate%29%29" class="RktStxLink" data-pltdoc="x">surrogate</a></span> form or <span class="RktVal">#f</span>, and it updates the field with its
|
||
|
argument; then, <span class="RktSym">set-surrogate</span> calls the <span class="RktSym">on-disable-surrogate</span> on the
|
||
|
previous value of the field and <span class="RktSym">on-enable-surrogate</span> for the
|
||
|
new value of the field. The <span class="RktSym">get-surrogate</span> method returns the
|
||
|
current value of the field.</p><p><div class="SIntrapara">If <span class="RktPn">#:use-wrapper-proc</span> does appear, the the host mixin adds
|
||
|
and a second private field and its getter and setter
|
||
|
methods <span class="RktSym">get-surrogate-wrapper-proc</span> and <span class="RktSym">set-surrogate-wrapper-proc</span>.
|
||
|
The additional field holds a wrapper procedure whose contract
|
||
|
is <span class="RktPn">(</span><span class="RktSym"><a href="function-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fbase..rkt%29._-~3e%29%29" class="RktStxLink" data-pltdoc="x"><span class="nobreak">-></span></a></span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym"><a href="function-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fbase..rkt%29._-~3e%29%29" class="RktStxLink" data-pltdoc="x"><span class="nobreak">-></span></a></span><span class="stt"> </span><span class="RktSym"><a href="data-structure-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fprivate%2Fmisc..rkt%29._any%29%29" class="RktStxLink" data-pltdoc="x">any</a></span><span class="RktPn">)</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym"><a href="function-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fbase..rkt%29._-~3e%29%29" class="RktStxLink" data-pltdoc="x"><span class="nobreak">-></span></a></span><span class="stt"> </span><span class="RktSym"><a href="data-structure-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fprivate%2Fmisc..rkt%29._any%29%29" class="RktStxLink" data-pltdoc="x">any</a></span><span class="RktPn">)</span><span class="stt"> </span><span class="RktSym"><a href="data-structure-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fprivate%2Fmisc..rkt%29._any%29%29" class="RktStxLink" data-pltdoc="x">any</a></span><span class="RktPn">)</span>, so the procedure is invoked with two thunks.
|
||
|
The first thunk is a fallback that invokes the original object’s method,
|
||
|
skipping the surrogate. The second thunk invokes the surrogate. The default
|
||
|
wrapper procedure is
|
||
|
</div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._~ce~bb%29%29" class="RktStxLink" data-pltdoc="x">λ</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">fallback-thunk</span><span class="hspace"> </span><span class="RktSym">surrogate-thunk</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">surrogate-thunk</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">That is, it simply defers to the method being invoked on the surrogate.
|
||
|
Note that wrapper procedure can adjust the
|
||
|
dynamic extent of calls to the surrogate
|
||
|
by, for example, changing the values of parameters. The
|
||
|
wrapper procedure is also invoked when calling the
|
||
|
<span class="RktSym">on-disable-surrogate</span> and <span class="RktSym">on-enable-surrogate</span> methods
|
||
|
of the surrogate.</div></p><p>The host mixin has a single overriding method for each
|
||
|
<span class="RktVar">method-id</span> in the <span class="RktSym"><a href="Surrogates.html#%28form._%28%28lib._racket%2Fsurrogate..rkt%29._surrogate%29%29" class="RktStxLink" data-pltdoc="x">surrogate</a></span> form (even the ones
|
||
|
specified with <span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._augment%29%29" class="RktStxLink" data-pltdoc="x">augment</a></span>). Each of these
|
||
|
methods is defined with a <span class="RktSym"><a href="lambda.html#%28form._%28%28quote._~23~25kernel%29._case-lambda%29%29" class="RktStxLink" data-pltdoc="x">case-lambda</a></span> with one arm for each
|
||
|
<span class="RktVar">arg-spec</span>. Each arm has the variables as arguments in the
|
||
|
<span class="RktVar">arg-spec</span>. The body of each method tests the
|
||
|
private surrogate field. If the field value is <span class="RktVal">#f</span>, the method just
|
||
|
returns the result of invoking the super or inner method. If the
|
||
|
field value is not <span class="RktVal">#f</span>, the corresponding method
|
||
|
of the object in the field is invoked. This method receives the same
|
||
|
arguments as the original method, plus two extras. The extra arguments
|
||
|
come at the beginning of the argument list. The first is the original
|
||
|
object. The second is a procedure that calls the super or inner method
|
||
|
(i.e., the method of the class that is passed to the mixin or an
|
||
|
extension, or the method in an overriding class), with the arguments
|
||
|
that the procedure receives.</p><p><div class="SIntrapara">For example, the host-mixin for this surrogate:
|
||
|
</div><div class="SIntrapara"><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym"><a href="Surrogates.html#%28form._%28%28lib._racket%2Fsurrogate..rkt%29._surrogate%29%29" class="RktStxLink" data-pltdoc="x">surrogate</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._override%29%29" class="RktStxLink" data-pltdoc="x">override</a></span><span class="hspace"> </span><span class="RktSym">m</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">z</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></p></blockquote></div><div class="SIntrapara">will override the <span class="RktSym">m</span> method and call the surrogate like this:
|
||
|
</div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._define%2Foverride%29%29" class="RktStxLink" data-pltdoc="x">define/override</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">m</span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">z</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="if.html#%28form._%28%28quote._~23~25kernel%29._if%29%29" class="RktStxLink" data-pltdoc="x">if</a></span><span class="hspace"> </span><span class="RktVar">surrogate</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="ivaraccess.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._send%29%29" class="RktStxLink" data-pltdoc="x">send</a></span><span class="hspace"> </span><span class="RktVar">surrogate</span><span class="hspace"> </span><span class="RktSym">m</span></td></tr><tr><td><span class="hspace"> </span><span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._this%29%29" class="RktStxLink" data-pltdoc="x">this</a></span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._~ce~bb%29%29" class="RktStxLink" data-pltdoc="x">λ</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">z</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._super%29%29" class="RktStxLink" data-pltdoc="x">super</a></span><span class="hspace"> </span><span class="RktSym">m</span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">z</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">z</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._super%29%29" class="RktStxLink" data-pltdoc="x">super</a></span><span class="hspace"> </span><span class="RktSym">m</span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">z</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">where <span class="RktVar">surrogate</span> is bound to the value most recently passed
|
||
|
to the host mixin’s <span class="RktSym">set-surrogate</span> method.</div></p><p>The host interface has the names <span class="RktSym">set-surrogate</span>,
|
||
|
<span class="RktSym">get-surrogate</span>, and each of the <span class="RktVar">method-id</span>s in the
|
||
|
original form.</p><p>The surrogate class has a single public method for each
|
||
|
<span class="RktVar">method-id</span> in the <span class="RktSym"><a href="Surrogates.html#%28form._%28%28lib._racket%2Fsurrogate..rkt%29._surrogate%29%29" class="RktStxLink" data-pltdoc="x">surrogate</a></span> form. These methods are
|
||
|
invoked by classes constructed by the mixin. Each has a corresponding
|
||
|
method signature, as described in the above paragraph. Each method
|
||
|
just passes its argument along to the super procedure it receives.</p><p><div class="SIntrapara">In the example above, this is the <span class="RktVar">m</span> method in the surrogate class:
|
||
|
</div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._define%2Fpublic%29%29" class="RktStxLink" data-pltdoc="x">define/public</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">m</span><span class="hspace"> </span><span class="RktSym">original-object</span><span class="hspace"> </span><span class="RktSym">original-super</span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">z</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">original-super</span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">z</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote></div></p><p>If you derive a class from the surrogate class, do not both call
|
||
|
the <span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._super%29%29" class="RktStxLink" data-pltdoc="x">super</a></span> argument and the super method of the surrogate
|
||
|
class itself. Only call one or the other, since the default methods
|
||
|
call the <span class="RktSym"><a href="createclass.html#%28form._%28%28lib._racket%2Fprivate%2Fclass-internal..rkt%29._super%29%29" class="RktStxLink" data-pltdoc="x">super</a></span> argument.</p><p>Finally, the interface contains all of the names specified in
|
||
|
surrogate’s argument, plus <span class="RktSym">on-enable-surrogate</span> and
|
||
|
<span class="RktSym">on-disable-surrogate</span>. The class returned by
|
||
|
<span class="RktSym"><a href="Surrogates.html#%28form._%28%28lib._racket%2Fsurrogate..rkt%29._surrogate%29%29" class="RktStxLink" data-pltdoc="x">surrogate</a></span> implements this interface.</p><div class="navsetbottom"><span class="navleft"><form class="searchform"><input class="searchbox" id="searchbox" type="text" tabindex="1" placeholder="...search manuals..." title="Enter a search string to search the manuals" onkeypress="return DoSearchKey(event, this, "8.6", "../");"/></form> <a href="https://docs.racket-lang.org/index.html" title="up to the documentation top" data-pltdoc="x" onclick="return GotoPLTRoot("8.6");">top</a><span class="tocsettoggle"> <a href="javascript:void(0);" title="show/hide table of contents" onclick="TocsetToggle();">contents</a></span></span><span class="navright"> <a href="objectutils.html" title="backward to "6.11 Object, Class, and Interface Utilities"" data-pltdoc="x">← prev</a> <a href="mzlib_class.html" title="up to "6 Classes and Objects"" data-pltdoc="x">up</a> <a href="mzlib_unit.html" title="forward to "7 Units"" data-pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html>
|