emacs.d/clones/lisp/www.cliki.net/Special Slots.html

99 lines
19 KiB
HTML
Raw Normal View History

2022-10-07 15:47:14 +02:00
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>CLiki: Special Slots</title>
<link rel="alternate" type="application/atom+xml" title="ATOM feed of edits to current article"
href="https://www.cliki.net/site/feed/article.atom?title=Special%20Slots">
<link rel="stylesheet" href="static/css/style.css">
<link rel="stylesheet" href="static/css/colorize.css">
</head>
<body>
<span class="hidden">CLiki - Special Slots</span>
<div id="content"><div id="content-area"><div id="article-title">Special Slots</div><div id="article">A kind of <a href="https://gitlab.common-lisp.net/dcooper/zacl/-/blob/master/fake-slots.lisp">pseudo-slot</a> where the value is stored in a hidden <a href="https://www.cliki.net/site/HyperSpec/Body/acc_symbol-value.html" class="hyperspec">symbol-value</a> outside of the instance. This means the special slot can be dynamically bound (using <a href="https://www.cliki.net/site/HyperSpec/Body/speope_progv.html" class="hyperspec">progv</a>) as a special variable would be. (The <tt>lets</tt> macro below is implemented with <a href="https://www.cliki.net/site/HyperSpec/Body/speope_progv.html" class="hyperspec">progv</a>.) There's a generic function (like <a href="https://www.cliki.net/site/HyperSpec/Body/stagenfun_slot-unbound.html" class="hyperspec">slot-unbound</a>) that will be called if the special slot is not bound. It would also be nice to have a concise way to specify the initial value for a special slot. Note that this code uses <a href="ORF.html" class="internal">ORF</a>, another <a href="macro&#32;example.html" class="category">macro example</a>.<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defparametercm_defvar.html" class="symbol"><i><span class="symbol">defvar</span></i></a> <span class="special">*special-slot-table*</span> <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_make-hash-table.html" class="symbol">make-hash-table</a></span>)</span>
<span class="string">"Map an instance to a plist of special slots."</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> ensure-special-slot <span class="paren2">(<span class="nonparen">instance accessor-name</span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">accessor-string <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_symbol-name.html" class="symbol">symbol-name</a> accessor-name</span>)</span></span>)</span></span>)</span>
<span class="paren3">(<span class="nonparen">orf <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_getf.html" class="symbol">getf</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_gethash.html" class="symbol">gethash</a> instance <span class="special">*special-slot-table*</span></span>)</span> accessor-name</span>)</span>
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_gensym.html" class="symbol">gensym</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a> <span class="string">"~A-~A"</span> accessor-string <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_string.html" class="symbol">string</a> '<a href="https://www.cliki.net/site/HyperSpec/Body/stagenfun_doc_umentationcp.html" class="symbol">variable</a></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defgeneric.html" class="symbol"><i><span class="symbol">defgeneric</span></i></a> special-slot-unbound <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/syscla_class.html" class="symbol">class</a> instance accessor-name</span>)</span>
<span class="paren2">(<span class="nonparen"><span class="keyword">:documentation</span> <span class="string">"Called when a special slot is not BOUNDP."</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="keyword">:method</span> <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/syscla_class.html" class="symbol">class</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_t.html" class="symbol">t</a></span>)</span> instance accessor-name</span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_error.html" class="symbol">error</a> 'unbound-special-slot
<span class="keyword">:instance</span> instance
<span class="keyword">:name</span> accessor-name</span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_define-condition.html" class="symbol"><i><span class="symbol">define-condition</span></i></a> unbound-special-slot <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/contyp_cell-error.html" class="symbol">cell-error</a></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">instance <span class="keyword">:initarg</span> <span class="keyword">:instance</span> <span class="keyword">:reader</span> unbound-special-slot-instance</span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="keyword">:report</span> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_lambda.html" class="symbol"><i><span class="symbol">lambda</span></i></a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/contyp_condition.html" class="symbol">condition</a> <a href="https://www.cliki.net/site/HyperSpec/Body/syscla_stream.html" class="symbol">stream</a> &amp;aux <span class="paren5">(<span class="nonparen">accessor-name <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_cell-error-name.html" class="symbol">cell-error-name</a> <a href="https://www.cliki.net/site/HyperSpec/Body/contyp_condition.html" class="symbol">condition</a></span>)</span></span>)</span></span>)</span>
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren5">(<span class="nonparen"><span class="paren6">(<span class="nonparen">special-slot-instance <span class="paren1">(<span class="nonparen">unbound-special-slot-instance <a href="https://www.cliki.net/site/HyperSpec/Body/contyp_condition.html" class="symbol">condition</a></span>)</span></span>)</span></span>)</span>
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/syscla_stream.html" class="symbol">stream</a> <span class="string">"The special slot ~S (associated with ~S) is unbound."</span>
accessor-name special-slot-instance</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defmacro.html" class="symbol"><i><span class="symbol">defmacro</span></i></a> <i><span class="symbol">define-special-slot</span></i> <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/stagenfun_class-name.html" class="symbol">class-name</a> accessor-name &amp;optional <a href="https://www.cliki.net/site/HyperSpec/Body/stagenfun_doc_umentationcp.html" class="symbol">documentation</a></span>)</span>
<span class="string">"Define a special slot on a class, optionally with documentation on the function."</span>
`<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_progn.html" class="symbol"><i><span class="symbol">progn</span></i></a> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defmethod.html" class="symbol"><i><span class="symbol">defmethod</span></i></a> ,accessor-name <span class="paren4">(<span class="nonparen"><span class="paren5">(<span class="nonparen">instance ,<a href="https://www.cliki.net/site/HyperSpec/Body/stagenfun_class-name.html" class="symbol">class-name</a></span>)</span></span>)</span>
,.<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_stringp.html" class="symbol">stringp</a> <a href="https://www.cliki.net/site/HyperSpec/Body/stagenfun_doc_umentationcp.html" class="symbol">documentation</a></span>)</span> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a> <a href="https://www.cliki.net/site/HyperSpec/Body/stagenfun_doc_umentationcp.html" class="symbol">documentation</a></span>)</span></span>)</span>
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren5">(<span class="nonparen"><span class="paren6">(<span class="nonparen">special-variable-name <span class="paren1">(<span class="nonparen">ensure-special-slot instance ',accessor-name</span>)</span></span>)</span></span>)</span>
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_cond.html" class="symbol"><i><span class="symbol">cond</span></i></a> <span class="paren6">(<span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_boundp.html" class="symbol">boundp</a> special-variable-name</span>)</span> <span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_symbol-value.html" class="symbol">symbol-value</a> special-variable-name</span>)</span></span>)</span>
<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_t.html" class="symbol">t</a> <span class="paren1">(<span class="nonparen">special-slot-unbound <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_class-of.html" class="symbol">class-of</a> instance</span>)</span> instance ',accessor-name</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="comment">;; Writer method is simpler because no worries about BOUNDP-ness.
</span> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defmethod.html" class="symbol"><i><span class="symbol">defmethod</span></i></a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_setf.html" class="symbol">setf</a> ,accessor-name</span>)</span> <span class="paren4">(<span class="nonparen">new-value <span class="paren5">(<span class="nonparen">instance ,<a href="https://www.cliki.net/site/HyperSpec/Body/stagenfun_class-name.html" class="symbol">class-name</a></span>)</span></span>)</span>
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_setf.html" class="symbol">setf</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_symbol-value.html" class="symbol">symbol-value</a> <span class="paren6">(<span class="nonparen">ensure-special-slot instance ',accessor-name</span>)</span></span>)</span>
new-value</span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> special-slot-makunbound <span class="paren2">(<span class="nonparen">instance accessor-name</span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_makunbound.html" class="symbol">makunbound</a> <span class="paren3">(<span class="nonparen">ensure-special-slot instance accessor-name</span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defmacro.html" class="symbol"><i><span class="symbol">defmacro</span></i></a> lets <span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">&amp;rest bindings</span>)</span> &amp;body body</span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> for <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">accessor-name instance</span>)</span> value</span>)</span> in bindings
for <a href="https://www.cliki.net/site/HyperSpec/Body/syscla_symbol.html" class="symbol">symbol</a> = `<span class="paren3">(<span class="nonparen">ensure-special-slot ,instance ',accessor-name</span>)</span>
collect <a href="https://www.cliki.net/site/HyperSpec/Body/syscla_symbol.html" class="symbol">symbol</a> into symbols collect value into <a href="https://www.cliki.net/site/HyperSpec/Body/any_values.html" class="symbol">values</a>
finally <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_return.html" class="symbol">return</a> `<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_progv.html" class="symbol"><i><span class="symbol">progv</span></i></a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a> ,.symbols</span>)</span> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a> ,.values</span>)</span>
,@body</span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defmacro.html" class="symbol"><i><span class="symbol">defmacro</span></i></a> lets* <span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">&amp;rest bindings</span>)</span> &amp;body body</span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_cond.html" class="symbol"><i><span class="symbol">cond</span></i></a> <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_endp.html" class="symbol">endp</a> bindings</span>)</span> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_listcm_listst.html" class="symbol">list*</a> '<a href="https://www.cliki.net/site/HyperSpec/Body/speope_progn.html" class="symbol"><i><span class="symbol">progn</span></i></a> body</span>)</span></span>)</span>
<span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_destructuring-bind.html" class="symbol">destructuring-bind</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_firstcm_s_inthcm_tenth.html" class="symbol">first</a> . <a href="https://www.cliki.net/site/HyperSpec/Body/acc_rest.html" class="symbol">rest</a></span>)</span> bindings
`<span class="paren5">(<span class="nonparen">lets <span class="paren6">(<span class="nonparen">,<a href="https://www.cliki.net/site/HyperSpec/Body/acc_firstcm_s_inthcm_tenth.html" class="symbol">first</a></span>)</span> <span class="paren6">(<span class="nonparen">lets* <span class="paren1">(<span class="nonparen">,@<a href="https://www.cliki.net/site/HyperSpec/Body/acc_rest.html" class="symbol">rest</a></span>)</span> ,@body</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span></div><p><a href="ContextL.html" class="internal">ContextL</a> has a more sophisticated (i.e. <a href="MOP.html" class="internal">MOP</a>-based) facility for <a href="https://github.com/pcostanza/contextl/blob/master/cx-special-class.lisp">special classes</a>.<p><a href="https://tfeb.github.io/tfeb-lisp-toys/#dynamic-bindings-for-fields-fluids"><tt>fluids</tt></a> are a similar idea, except that a "fluid" is a CLOS object, not a symbol.<p><hr>
<a href="Apache&#32;2.html" class="category">Apache 2</a></div></div>
<div id="footer" class="buttonbar"><ul><li><a href="Special&#32;Slots.html">Current version</a></li>
<li><a href="https://www.cliki.net/site/history?article=Special%20Slots">History</a></li>
<li><a href="https://www.cliki.net/site/backlinks?article=Special%20Slots">Backlinks</a></li><li><a href="https://www.cliki.net/site/edit-article?title=Special%20Slots&amp;from-revision=3853800861">Edit</a></li><li><a href="https://www.cliki.net/site/edit-article?create=t">Create</a></li></ul></div>
</div>
<div id="header-buttons" class="buttonbar">
<ul>
<li><a href="https://www.cliki.net/">Home</a></li>
<li><a href="https://www.cliki.net/site/recent-changes">Recent Changes</a></li>
<li><a href="CLiki.html">About</a></li>
<li><a href="Text&#32;Formatting.html">Text Formatting</a></li>
<li><a href="https://www.cliki.net/site/tools">Tools</a></li>
</ul>
<div id="search">
<form action="https://www.cliki.net/site/search">
<label for="search_query" class="hidden">Search CLiki</label>
<input type="text" name="query" id="search_query" value="" />
<input type="submit" value="search" />
</form>
</div>
</div>
<div id="pageheader">
<div id="header">
<span id="logo">CLiki</span>
<span id="slogan">the common lisp wiki</span>
<div id="login"><form method="post" action="https://www.cliki.net/site/login">
<label for="login_name" class="hidden">Account name</label>
<input type="text" name="name" id="login_name" class="login_input" />
<label for= "login_password" class="hidden">Password</label>
<input type="password" name="password" id="login_password" class="login_input" />
<input type="submit" name="login" value="login" id="login_submit" /><br />
<div id="register"><a href="https://www.cliki.net/site/register">register</a></div>
<input type="submit" name="reset-pw" value="reset password" id="reset_pw" />
</form>
</div>
</div>
</div>
</body></html>