

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>sykosomatic</title>
	<atom:link href="http://sykosomatic.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://sykosomatic.org</link>
	<description>Programming, web technologies, game design, and Free Software</description>
	<lastBuildDate>Tue, 27 Sep 2011 05:46:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
	<atom:link rel='hub' href='http://sykosomatic.org/?pushpress=hub'/>
		<item>
		<title>Pivot tables in PostgreSQL</title>
		<link>http://sykosomatic.org/2011/09/pivot-tables-in-postgresql/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2011/09/pivot-tables-in-postgresql/#comments</comments>
		<pubDate>Mon, 26 Sep 2011 23:20:16 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=107</guid>
		<description><![CDATA[A common complaint with relational databases is their lack of flexibility. This &#8216;lack&#8217; of flexibility has been one of the drivers behind the NoSQL movement. As it turns out, though, there are tools and tricks that can be used with existing RDBMSs that could help you leverage the maturity, tool support, and performance of these [...]]]></description>
			<content:encoded><![CDATA[<p>A common complaint with relational databases is their lack of flexibility. This &#8216;lack&#8217; of flexibility has been one of the drivers behind the NoSQL movement. As it turns out, though, there are tools and tricks that can be used with existing RDBMSs that could help you leverage the maturity, tool support, and performance of these systems while still achieving the flexibility you might need with your application. One such trick is the usage of pivot tables.<br />
<span id="more-107"></span><br />
Pivot tables are a querying strategy that allows you to &#8216;flatten&#8217; multiple rows into multiple rows of multiple columns. For example, consider the following two table definitions:</p>
<pre class="prettyprint lang-sql">
CREATE TABLE user_account (
   id SERIAL,
   email TEXT
);

CREATE TABLE user_attribute (
   user_account_id BIGINT,
   attribute_type TEXT,
   value TEXT
);
</pre>
<p>Using these two tables, we can, at least temporarily, punt on finding an ideal table representation for all users ever. Sure, we&#8217;re assuming all <code class="prettyprint lang-sql">user_account</code>s will have an email, but for the sake of this example I want an excuse to do a join, so let it be. ;)</p>
<p>This is a very data-driven approach, where all one has to do to extend a conceptual object (in this case a user) is to add an attribute/property to it. If you don&#8217;t need it right now, your code doesn&#8217;t even need to change, but you can store it. You could even provide non-programmers with an interface into this system for extending your schema without a single bit of SQL anywhere in sight.</p>
<p>Here&#8217;s a simple user:</p>
<pre class="prettyprint lang-sql">
INSERT INTO user_account (email) VALUES ('foo@example.com');
INSERT INTO user_attribute
     (user_account_id, attribute_type, value)
   VALUES
     (1,'first-name','John'),
     (1,'last-name','Doe'),
     (1,'title','Dr');
</pre>
<p>Of course, now the problem is constructing a complete &#8216;view&#8217; for these users that includes these attributes. We&#8217;d like to have one row per user, with all its attributes in individual columns. A basic join won&#8217;t really get us what we want, though:</p>
<pre class="prettyprint lang-sql">
db=# select id,email,attribute_type,value from user_account inner join user_attribute on id = user_account_id where email = 'foo@example.com';
 id |      email      | attribute_type | value
----+-----------------+----------------+-------
  1 | foo@example.com | first-name     | John
  1 | foo@example.com | last-name      | Doe
  1 | foo@example.com | title          | Dr
(3 rows)
</pre>
<p>Enter pivot tables. There&#8217;s a number of ways to do them. My favorite involves the <code class="prettyprint lang-sql">CASE</code> statement combined with an aggregate and <code class="prettyprint lang-sql">GROUP BY</code>. Here&#8217;s how it would apply to our example:</p>
<pre class="prettyprint lang-sql">
SELECT -- Grab the user_account columns.
       acc.id,
       acc.email,
       -- Use max() combined with a case statement to
       -- usher individual attribute values into columns.
       max(CASE WHEN (attr.attribute_type = 'first-name')
                THEN attr.value END) AS fname,
       max(CASE WHEN (attr.attribute_type = 'last-name')
                THEN attr.value END) AS lname,
       max(CASE WHEN (attr.attribute_type = 'title')
                THEN attr.value END) AS title
   FROM user_account AS acc
   -- Join the attribute table /once/.
   LEFT JOIN user_attribute AS attr
     ON (attr.user_account_id = acc.id)
   WHERE (acc.email = 'foo@example.com')
   -- Group by the non-pivoted columns
   GROUP BY acc.id,acc.email;
</pre>
<p>Which gives us the single-row results we wanted:</p>
<pre class="prettyprint lang-sql">
 id |      email      | fname | lname | title
----+-----------------+-------+-------+-------
  1 | foo@example.com | John  | Doe   | Dr
(1 row)
</pre>
<p>And there you have it. Of course, it&#8217;s not the prettiest way to generate this kind of output. Still, it&#8217;s a lot better than doing multiple queries and combining results in your application, and it would be easy to convert these queries into super-fast materialized views if performance ever becomes an issue.</p>
<p>Fortunately, PostgreSQL ships with a tablefunc module with a utility that makes this sort of data transformation easy &#8212; and even converts data types for you! You can read more about the <code class="prettyprint lang-sql">crosstab()</code> function on the <a href="http://www.postgresql.org/docs/current/static/tablefunc.html">Postgres documentation page for tablefunc.</a> That page also includes a number of compelling use cases for pivot tables.</p>
<p>I&#8217;ve used pivot tables in applications I&#8217;ve worked on to do things such as pivoting on a large variety of external id codes as well as to define a relatively flexible name-specification system for a game. Have you used a similar trick with SQL? Do other SQL systems have similar utilities for generating pivot tables?</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2011/09/pivot-tables-in-postgresql/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Chillax and Protocols</title>
		<link>http://sykosomatic.org/2010/10/chillax-and-protocols/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2010/10/chillax-and-protocols/#comments</comments>
		<pubDate>Sun, 31 Oct 2010 03:03:28 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[protocols]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=92</guid>
		<description><![CDATA[Funny how a full-time job can pull you away from everything else&#8230; I recently did a major rewrite of Chillax. It&#8217;s funny what they say about Common Lisp, how you never finish learning it. Ever since I started using it, I&#8217;ve gotten periodic &#8220;aha!&#8221; moments where something simply clicks. A memorable example was the moment [...]]]></description>
			<content:encoded><![CDATA[<p>Funny how a full-time job can pull you away from everything else&#8230;</p>
<p>I recently did a major rewrite of <a href="http://github.com/sykopomp/chillax">Chillax</a>. It&#8217;s funny what they say about Common Lisp, how you never finish learning it. Ever since I started using it, I&#8217;ve gotten periodic &#8220;aha!&#8221; moments where something simply clicks. A memorable example was the moment when macros really made sense. The latest one, which came to me while working on Chillax, was the idea of designing your program around protocols.<br />
<span id="more-92"></span><br />
Now, protocols are nothing new, and nothing unique to Lisp. CL doesn&#8217;t even have &#8216;explicit&#8217; protocol support, like Clojure or Haskell do (although there&#8217;s a <a href="http://common-lisp.net/cgi-bin/viewcvs.cgi/protocols/?root=rjain-utils">library</a>). It does, though, have generic functions. &#8220;Write your code around defgeneric, not around defclass&#8221; is certainly something that gets regurgitated over and over. <a href="http://gigamonkeys.com/book">PCL</a> even emphasizes the point by introducing generic functions before it even introduces CLOS classes.</p>
<p>Still, it&#8217;s not something that seems to stick right away for everyone. It certainly didn&#8217;t stick for me for a couple of years. Then it did &#8212; and it was like a tidal wave had just washed over me.</p>
<p>Consider this piece of code:</p>
<pre class="prettyprint lang-lisp">(defclass server ()
  ((host :accessor host :initarg :host :initform &quot;127.0.0.1&quot;)
   (port :accessor port :initarg :port :initform 5984)
   (username :accessor username :initarg :username :initform nil)
   (password :accessor password :initarg :password :initform nil)
   (securep :accessor securep :initarg :securep :initform nil)))

(defmethod couch-request ((server server) uri)
   ...)

(defmethod stats ((server server))
  (couch-request server &quot;_stats&quot;))

... etc ...</pre>
<p>Seems reasonable enough. in fact, a lot of &#8220;Object-oriented&#8221; code kinda flows like this. You first think of what kind of object you want to describe, and create a new class that has data fields that sort of describe that &#8216;object&#8217;, then you write methods for that class. The hope here is that you can just inherit from whatever class, and everything will be okay.</p>
<p>Unfortunately, there are a number of problems with this approach:</p>
<ol>
<li>It &#8216;covers its bases&#8217; by just defining blanket accessors, initargs, and initforms for slots. This is both unnecessary and verbose.</li>
<li>it creates potentially-unnecessary slots. &#8212; What if your subclass wants to store this data elsewhere, or construct it programmatically?</li>
<li>The only way to reuse code is to subclass my-class. There&#8217;s perfectly reusable code there that is now stuck in a class-specific method.</li>
</ol>
<p>We&#8217;re constantly being told about how object-orientation can make our code reusable and extensible &#8212; but this doesn&#8217;t seem very extensible at all!</p>
<p>Enter protocols: You design your program generically &#8212; that means, you don&#8217;t assume anything about the objects it handles except what it is -necessary- for the objects to be able to do. The rest of the code doesn&#8217;t even need to be polymorphic. After figuring out what the fuss with protocols was about, this is what the above Chillax code transformed into:</p>
<pre class="prettyprint lang-lisp">(defgeneric server-host (server))
(defgeneric server-port (server))
(defgeneric server-username (server))
(defgeneric server-password (server))
(defgeneric server-secure-p (server))
(defgeneric data-&gt;json (server data &amp;key)
  (:documentation &quot;Converts DATA to JSON suitable for sending to CouchDB.&quot;))
(defgeneric json-&gt;data (server json &amp;key)
  (:documentation &quot;Converts JSON to the desired data structure.&quot;))

(defun couch-request (server uri &amp;key convert-data-p &amp;allow-other-keys)
  ... code ...)

(defun server-uri (server)
  (format nil &quot;~A://~A:~A/&quot;
             (if (server-secure-p server)
                 &quot;https&quot;
                 &quot;http&quot;)
             (server-host server)
             (server-port server)))

(defun couch-request (server uri)
  ... implementation using protocol ...)

(defun stats (server)
  (couch-request server &quot;_stats&quot;))

... etc ...</pre>
<p>But that&#8217;s not the full implementation, is it? It&#8217;s not &#8212; but it&#8217;s the vast majority of the code needed in order to use the Chillax API. The magic happens when you realize how much implementation is needed to take advantage of this:</p>
<pre class="prettyprint lang-lisp">(defclass standard-server ()
  ((host
    :reader server-host
    :initarg :host
    :initform &quot;127.0.0.1&quot;)
   (port
    :reader server-port
    :initarg :port
    :initform 5984)
   (username
    :reader server-username
    :initarg :username
    :initform nil)
   (password
    :reader server-password
    :initarg :password
    :initform nil)
   (securep
    :reader server-secure-p
    :initarg :securep
    :initform nil))
  (:documentation
   &quot;Default implementation of the server protocol.&quot;))

(defmethod data-&gt;json ((server standard-server) data &amp;key)
  data)
(defmethod json-&gt;data ((server standard-server) json &amp;key)
  json)

(stats (make-instance 'standard-server)) =&gt; { server stats }</pre>
<p>That&#8217;s really all of it. The beauty here is that you can reuse code without dealing with inheritance, or any sort of class-based hierarchy. Doesn&#8217;t seem like a big deal? Consider that CLOS allows you to define methods on built-in classes:</p>
<pre class="prettyprint lang-lisp">(defmethod server-host ((server hash-table)) (gethash 'host server))
(defmethod server-port ((server hash-table)) (gethash 'port server))
...and so on...

(let ((server (make-hash-table)))
  (setf (gethash 'host server) &quot;127.0.0.1&quot;
         (gethash 'port server) 5984)
  (stats server)) =&gt; { server stats }</pre>
<p>As long as you tell Chillax how to do what it needs to do on your own data types, it can take care of everything else.</p>
<p>I really like what this ended up doing to Chillax&#8217;s API. It&#8217;s made it very easy to reuse most of the Chillax code while still swapping out JSON libraries, and possibly (but not yet) http clients.</p>
<p>If you want to read more about protocols, I highly recommend you check out <a href="http://www.amazon.com/Art-Metaobject-Protocol-Gregor-Kiczales/dp/0262610744">Art of the Metaobject Protocol</a>. I have not read it yet myself (it&#8217;s been on my desk for a while), but <a href="http://www.amazon.com/Object-Oriented-Programming-Common-Lisp-Programmers/dp/0201175894">Sonya Keene&#8217;s CLOS book</a> is also recommended fairly often.</p>
<p>If you&#8217;re interested in reading about other languages&#8217; takes on this concept, go read up on Haskell&#8217;s <a href="http://en.wikipedia.org/wiki/Type_class">Type Classes</a>, <a href="http://en.wikipedia.org/wiki/Java_interface">Java&#8217;s Interfaces</a>, and Clojure&#8217;s <a href="http://clojure.org/Protocols">Protocols</a>. Common Lisp itself also has various examples of &#8216;protocol-oriented&#8217; APIs, such as Gray Streams, and the more recent <a href="http://www.doc.gold.ac.uk/~mas01cr/papers/ilc2007/sequences-20070301.pdf">extensible sequences protocol</a> in SBCL.</p>
<p>If you want to read about more interesting, advanced uses of this architectural technique, François-René Rideau&#8217;s postings about <a href="http://fare.livejournal.com/tag/interface-passing%20style">&#8220;Interface-passing Style&#8221;</a> are good reads (and so is his <a href="http://common-lisp.net/gitweb?p=users/frideau/fare-utils.git;a=summary">fare-utils</a> code).</p>
<p>Of course, I&#8217;ve left a small detail out: How do you actually design programs incrementally like this? The fact is that protocols are not always immediately obvious, and they&#8217;re not necessarily static as your application evolves. The process of writing extensible code using protocols is often incremental, and half of AMOP is dedicated to describing techniques for growing and developing these.</p>
<p>Do you write code like this? How has it worked out for you?</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2010/10/chillax-and-protocols/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>CouchDB: Making databases fun</title>
		<link>http://sykosomatic.org/2009/12/couchdb-making-databases-fun/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2009/12/couchdb-making-databases-fun/#comments</comments>
		<pubDate>Fri, 25 Dec 2009 06:47:15 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[couchdb]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[nosql]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=89</guid>
		<description><![CDATA[So the whole reason I even started writing Sheeple was to use it as a persistent object backend for Sykosomatic, that MUD that I&#8217;ve been sort-of writing since I started working on Lisp, but is still unfinished. Sheeple is a very dynamic system, and so when I went looking for a database backend to build [...]]]></description>
			<content:encoded><![CDATA[<p>So the whole reason I even started writing Sheeple was to use it as a persistent object backend for Sykosomatic, that MUD that I&#8217;ve been sort-of writing since I started working on Lisp, but is still unfinished.</p>
<p>Sheeple is a very dynamic system, and so when I went looking for a database backend to build this persistence library around, most things fell short of my expectations&#8230; and then I found <a href="http://en.wikipedia.org/wiki/Couchdb">CouchDB</a>.<br />
<span id="more-89"></span><br />
I don&#8217;t think I can praise CouchDB enough. Everything about it  so far has just been a dream. After a week of nightmarish interactions with SQL (on a different project), nothing was a bigger blessing than CouchDB&#8217;s easy, wonderful, simple design.</p>
<p>Everything about Couch just reeks of ease-of-use and simplicity. You don&#8217;t need anything fancy. No obnoxious authentication setup or all that bullshit MySQL makes you go through just so you can put your grandma&#8217;s phone number into a goddamn table. No ridiculous, pathetic attempts at making your object model fit in with your schema. No obnoxious &#8216;drivers&#8217; and weird serialization formats to deal with.</p>
<p>All you need to do to get started with CouchDB is a single command to install it through your package manager, start up the daemon, and start throwing http requests at it with curl or something.</p>
<p>That&#8217;s it. That&#8217;s all. CouchDB daemon + http client + JSON library, and you&#8217;re GOOD TO GO. If you want to wrap that up and make it object-oriented or something, that&#8217;s -trivial-. You can tell from the moment you start reading their <a href="http://wiki.apache.org/couchdb/">documentation</a>, or <a href="http://books.couchdb.org/relax/">the wonderful, but apparently still WIP book</a>, that the CouchDB designers have put a lot of effort into making life easy for you. They really do live up to their motto: Relax.</p>
<p>CouchDB has been a dream to work with &#8212; it&#8217;s easy to get set up, easy to use, and easy to manage, all-around. Sure, a big benefit comes just from the fact that CouchDB is one of those shiny new <a href="http://en.wikipedia.org/wiki/Nosql">NoSQL databases</a>. Couch, though, goes the extra mile for you. You know what I don&#8217;t want to do? I don&#8217;t want a <a href="http://www.mongodb.org/display/DOCS/Mongo+Driver+Requirements">&#8216;driver&#8217;</a>. I don&#8217;t want<a href="http://www.mongodb.org/display/DOCS/BSON"> BSON</a>.</p>
<p>You know what I do want? I want to go play with CouchDB some more &#8212; and you should too.</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2009/12/couchdb-making-databases-fun/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Sheeple 3.0.3</title>
		<link>http://sykosomatic.org/2009/12/sheeple-3-0-3/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2009/12/sheeple-3-0-3/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 17:54:07 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[announcements]]></category>
		<category><![CDATA[lisp]]></category>
		<category><![CDATA[sheeple]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=88</guid>
		<description><![CDATA[Adlai said we should make an emergency release of Sheeple, since he added effective reply function caching. I agreed. If you do -any- sort of semi-serious data crunching using Sheeple, stay the hell away from 3.0.2!]]></description>
			<content:encoded><![CDATA[<p>Adlai said we should make an emergency release of Sheeple, since he added effective reply function caching. I agreed. If you do -any- sort of semi-serious data crunching using Sheeple, stay the hell away from 3.0.2!</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2009/12/sheeple-3-0-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sheeple 3.0.2</title>
		<link>http://sykosomatic.org/2009/12/sheeple-3-0-2/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2009/12/sheeple-3-0-2/#comments</comments>
		<pubDate>Tue, 15 Dec 2009 23:44:57 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[announcements]]></category>
		<category><![CDATA[lisp]]></category>
		<category><![CDATA[metaprogramming]]></category>
		<category><![CDATA[object-oriented programming]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[sheeple]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=85</guid>
		<description><![CDATA[It&#8217;s taken a while to get this release out &#8212; we kept adding stuff on &#8212; but it&#8217;s finally out. Even though it&#8217;s a minor version bump, there&#8217;s some important API changes with this new version, including the complete removal of ADD-PROPERTY. Originally, I thought it would be a good idea to force users to [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s taken a while to get this release out &#8212; we kept adding stuff on &#8212; but it&#8217;s finally out. Even though it&#8217;s a minor version bump, there&#8217;s some important API changes with this new version, including the complete removal of ADD-PROPERTY. Originally, I thought it would be a good idea to force users to add a property manually before being allowed to set a value. Then I realized that the Python community has had this ability for a very long time. The freenode Pythonistas seemed to pretty consistently agree that it had never caused serious problems. Thus, A-P is gone, and (SETF PROPERTY-VALUE) is now used to both add a property, and to set a value on existing ones.</p>
<p>There is also now a manual! A pretty one in both PDF and HTML form, which can be found at our <a href="http://common-lisp.net/project/sheeple">new project page on common-lisp.net</a>. There&#8217;s also some mailing lists on that page you might want to sign up for if you feel like tracking Sheeple development.</p>
<p>Things have slowly been ramping up. Ever since I gave <a href="http://vimeo.com/7242003">that talk at the TC Lispers meeting</a>, a few other people have given Sheeple a whirl. I&#8217;m pleased that their experiences have been good, even though Sheeple is still a bit unstable. Of particular note is <a href="http://nklein.com/2009/12/woolly-application-underway/">Patrick Stein&#8217;s Wooly</a>, a GL-based GUI toolkit using Sheeple objects.</p>
<p>Development has slowed down a bit since I started working at <a href="http://clockwork.net">Clockwork</a>, but I&#8217;ve been working with Adlai lately towards a native-Sheeple MOP. So far, the basics of object creation have been taken care of, and a property MOP should be up and running soon. We&#8217;ve also decided to rename persistent-sheeple, but that will get announced once we have enough of a MOP to hook up our objects to CouchDB.</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2009/12/sheeple-3-0-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Release: Sheeple 3.0</title>
		<link>http://sykosomatic.org/2009/10/release-sheeple-3-0/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2009/10/release-sheeple-3-0/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 10:34:12 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[announcements]]></category>
		<category><![CDATA[lisp]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[sheeple]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=79</guid>
		<description><![CDATA[Sheeple 3.0 is finally out! After months in development, it&#8217;s finally done. A major rewrite of the entire Sheeple system, this new version boasts a completely new, cleaned up, and serious&#8217;d interface, reworked, lightweight objects, and efficient property access (right now, matching CCL&#8217;s slot-value performance.) You can download a tarball here, or use asdf-install to [...]]]></description>
			<content:encoded><![CDATA[<p>Sheeple 3.0 is finally out!</p>
<p>After months in development, it&#8217;s finally done. A major rewrite of the entire Sheeple system, this new version boasts a completely new, cleaned up, and serious&#8217;d interface, reworked, lightweight objects, and efficient property access (right now, matching CCL&#8217;s slot-value performance.) You can download a tarball <a title="sheeple downloads page" href="http://github.com/sykopomp/sheeple/downloads">here</a>, or use <a href="http://www.cliki.net/ASDF-Install">asdf-install</a> to grab the latest version.</p>
<p>I&#8217;m really excited about this release. I would write more about it and all the goodies it has, but I have a<a title="Sheeple presentation!" href="http://tclispers.org/events/october-meeting"> presentation</a> to finish. Expect more in a later post.</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2009/10/release-sheeple-3-0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick Sheeple update&#8230;</title>
		<link>http://sykosomatic.org/2009/10/quick-sheeple-update/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2009/10/quick-sheeple-update/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 07:20:38 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[random]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[sheeple]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=72</guid>
		<description><![CDATA[Okay, so I haven&#8217;t actually posted anything about Sheeple in a while. Sheeple took a break for a few weeks, but development is up to full steam again. There&#8217;s some shiny new special sauce going on under the hood now, with some -very- promising early results. See this paste for some picobenchmarks on various implementation. [...]]]></description>
			<content:encoded><![CDATA[<p>Okay, so I haven&#8217;t actually posted anything about Sheeple in a while.</p>
<p>Sheeple took a break for a few weeks, but development is up to full steam again. There&#8217;s some shiny new special sauce going on under the hood now, with some -very- promising early results.</p>
<p>See <a title="omg-optimized" href="http://paste.lisp.org/display/88658">this paste</a> for some picobenchmarks on various implementation. Notice: direct-property access is now as fast as slot-value on CCL. :)</p>
<p>Unfortunately, the rest of Sheeple doesn&#8217;t perform that well quite yet. The new fancy secret sauce allows for a lot of optimizations that weren&#8217;t done before. Once this code is stabilized and tagged as 3.0(!), I&#8217;m bringing back a bunch of different caching schemes Sheeple was using for dispatch. Tonight&#8217;s benchmarks were promising &#8212; I think Sheeple may actually be able to perform better and faster than optimized CLOS implementations such as CCL&#8217;s and SBCL&#8217;s.</p>
<p>We&#8217;ll see. We&#8217;ll see&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2009/10/quick-sheeple-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing: ChanL</title>
		<link>http://sykosomatic.org/2009/10/introducing-chanl/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2009/10/introducing-chanl/#comments</comments>
		<pubDate>Wed, 14 Oct 2009 20:50:09 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[random]]></category>
		<category><![CDATA[chanl]]></category>
		<category><![CDATA[communicating sequential processes]]></category>
		<category><![CDATA[concurrency]]></category>
		<category><![CDATA[lisp]]></category>
		<category><![CDATA[threads]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=70</guid>
		<description><![CDATA[For the longest time, I wanted to start learning about issues related to concurrency, and how to handle them in Lisp. I kept reading around to learn about different approaches to writing concurrent code, and studied up on things like Software Transactional Memory, futures/promises, and Erlang-style actors. After boggling to understand all these different approaches, [...]]]></description>
			<content:encoded><![CDATA[<p>For the longest time, I wanted to start learning about issues related to concurrency, and how to handle them in Lisp. I kept reading around to learn about different approaches to writing concurrent code, and studied up on things like <a title="STM" href="http://en.wikipedia.org/wiki/Software_transactional_memory">Software Transactional Memory</a>, <a title="futs" href="http://en.wikipedia.org/wiki/Futures_and_promises">futures/promises</a>, and <a title="the language" href="http://en.wikipedia.org/wiki/Erlang_(programming_language)">Erlang</a>-style <a title="the model" href="http://en.wikipedia.org/wiki/Actor_model">actors</a>. After boggling to understand all these different approaches, I was left with a bit of disappointment: None of them seemed to be the right combination of generalized+clean+easy.</p>
<p>STM caught my eye for a while, but it still has its issues, and I&#8217;m still not sure how I feel about the whole &#8220;thrash until you can agree on something&#8221; issue &#8212; it seems to me like it&#8217;s just the same as wrapping code in  (with-lock-held &#8230;). Futures/promises looked easy enough for simple one-shot tasks, but that&#8217;s not necessarily what you want to do when you write heavily-parallel code: Sometimes you want threads constantly yielding values. Erlang-style actors are, of course, one of the big success stories when it comes to people trying to write heavily-parallel code. It just seems so damn ugly &#8212; and it -is- nice to be able to share data sometimes.</p>
<p>Then, magic happened: I came across something called <a title="CSP" href="http://en.wikipedia.org/wiki/Communicating_sequential_processes">Communicating Sequential Processes</a>, through <a title="tech talk" href="http://video.google.com/videoplay?docid=810232012617965344#">Rob Pike&#8217;s Google Tech Talk on Newsqueak</a>. It was really amazing, it seemed to be just what I needed: a relatively low-level synchronisation mechanism that works naturally with the concept of multiple parallel threads/processes. I&#8217;m totally sold on Rob&#8217;s point of view here: don&#8217;t try to pretend you&#8217;re not parallelizing code (hear that, STM? That&#8217;s right). Instead, make the parallelization part of your interface. Deadlocks are a bug &#8212; find them.<br />
<span id="more-70"></span><br />
I spent a good while thinking about CSP, wondering why the heck everything else is the talk of the town. The more I thought about it, the more I was amazed that CSP wasn&#8217;t everyone&#8217;s obvious choice when it came to parallelization. I kept wondering why no one seemed to even know about it. Then again, it&#8217;s not entirely obscure &#8212; <a title="stackless" href="http://en.wikipedia.org/wiki/Stackless_Python">Stackless Python</a> uses this exact same concept. Clearly, the only way I could really get a good idea of what CSP is all about, and what its advantages/disadvantages are was by actually using it.</p>
<p>As it turns out, there was already an existing library for CL that implemented these: <a title="csp library" href="http://www.cliki.net/csp">csp</a>. The API, unfortunately, was a bit weird, and I couldn&#8217;t get myself into really using. I just didn&#8217;t get it &#8212; is CSP a red herring meant to distract me from some other Right Thing? I figured the only way to find out, then, would be to implement my own library.</p>
<p>Enter ChanL, my attempt at implementing channels in CL. I&#8217;ve been working with Adlai on these for a couple of weeks, and we just tagged v0.4. As the library developed, and we started writing examples, things started becoming more and more clear. Channels, as it turns out, are just high-level enough to make a lot of tasks extremely easy that would otherwise be a bit obnoxious to write with locks.Well, sort of: it turns out to be a little tricky to convert existing, very-linear code into channels unless you&#8217;re used to them (STM certainly wins in that front, I have to say)&#8230; but once you&#8217;ve embraced the concurrent nature of your algorithm, channels become a powerful beast.</p>
<p>The most interesting part, I think, is that channels turned out to be extremely useful for implementing -other- sorts of (sometimes simpler) concurrency mechanisms. Futures/promises, for example, were implemented in about 20 lines of code. The whole chanl/examples/futures.lisp file is 93 lines long, including comments, several convenience macros for creating futures, a select function, and a parallelized version of LET, as well as a fully-functional cross-thread condition-handling mechanism. That&#8217;s a lot of stuff, and it was made simple because of how nice channels are. Actors can be implemented similarly, and, in fact, I&#8217;m working on them already, although the code isn&#8217;t online yet.</p>
<p>All-in-all, after working with channels for a few weeks, my impression is that they&#8217;re much closer to a generalizable solution to handling concurrency than all these other constructs that keep popping up (again, perhaps with the exception of STM, which has different issues). I&#8217;m still honestly perplexed as to why channels aren&#8217;t more widely accepted and used. Perhaps it&#8217;s high time that changed.</p>
<p>If you ever feel like messing around with channels, go ahead and try it out. It&#8217;s asdf-installable with (asdf-install:install :chanl), or you can download it at <a title="github chanl download" href="http://github.com/sykopomp/chanl/downloads">Github</a>. It&#8217;s got a fully-documented API, and you can even write your own unique channel styles fairly easily.</p>
<p>Next time: ChanL code samples/examples.</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2009/10/introducing-chanl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sheeple goes on a diet</title>
		<link>http://sykosomatic.org/2009/08/sheeple-goes-on-a-diet/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2009/08/sheeple-goes-on-a-diet/#comments</comments>
		<pubDate>Fri, 14 Aug 2009 06:15:35 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[random]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=68</guid>
		<description><![CDATA[I&#8217;ve been working on rewriting Sheeple these past couple of days. The new version will be a major bottom-up redesign, mainly to the lowlevel stuff. The early results without too-crazy optimization are already showing up, and it&#8217;s quite nice. These numbers are on Clozure CL x86  Linux: SHEEPLE&#62; (time (loop repeat 100000 do (allocate-std-sheep))) (LOOP [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on rewriting Sheeple these past couple of days. The new version will be a major bottom-up redesign, mainly to the lowlevel stuff. The early results without too-crazy optimization are already showing up, and it&#8217;s quite nice.</p>
<p>These numbers are on Clozure CL  x86  Linux:</p>
<pre>SHEEPLE&gt; (time (loop repeat 100000 do (allocate-std-sheep)))
(LOOP REPEAT 100000 DO (ALLOCATE-STD-SHEEP)) took 119 milliseconds (0.119 seconds) to run
                    with 2 available CPU cores.
During that period, 106 milliseconds (0.106 seconds) were spent in user mode
                    3 milliseconds (0.003 seconds) were spent in system mode
50 milliseconds (0.050 seconds) was spent in GC.
 4,000,000 bytes of memory allocated.
 19 minor page faults, 0 major page faults, 0 swaps.</pre>
<p>And a single sheep object:</p>
<pre>SHEEPLE&gt; (time (allocate-std-sheep))
(ALLOCATE-STD-SHEEP) took 0 milliseconds (0.000 seconds) to run
                    with 2 available CPU cores.
During that period, 0 milliseconds (0.000 seconds) were spent in user mode
                    0 milliseconds (0.000 seconds) were spent in system mode
 40 bytes of memory allocated.</pre>
<p>Now, that&#8217;s still a bit heavy compared to CLOS (which only allocates 24 bytes for a raw instance), and to be honest, I&#8217;m not aiming at beating CLOS. It&#8217;s like a class-based system trying to beat out structs. On the other hand, it&#8217;s actually pretty nice to shrink everything down to more usable levels.<br />
The current Sheeple release, for example, the one built on top of CLOS, is quite a monster:</p>
<pre>SHEEPLE&gt; (time (loop repeat 100000 do (allocate-sheep)))
(LOOP REPEAT 100000 DO (ALLOCATE-SHEEP)) took 11,273 milliseconds (11.273 seconds) to run
                    with 2 available CPU cores.
During that period, 10,716 milliseconds (10.716 seconds) were spent in user mode
                    204 milliseconds (0.204 seconds) were spent in system mode
3,249 milliseconds (3.249 seconds) was spent in GC.
 244,000,000 bytes of memory allocated.
 9,419 minor page faults, 0 major page faults, 0 swaps.</pre>
<p>So yeah, this is a huge improvement.</p>
<p>Keep in mind that all of these numbers don&#8217;t yet take into account what the full cost of a raw (clone) will be, although it won&#8217;t be much higher than what it is right now (I believe it will only be two extra words, because an item will be added to the parents list).</p>
<p>It&#8217;s a bit fun to mess around with stuff so carefully at a lower level&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2009/08/sheeple-goes-on-a-diet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sheeple MOP</title>
		<link>http://sykosomatic.org/2009/08/sheeple-mop/?&#038;owa_medium=feed&#038;owa_sid=</link>
		<comments>http://sykosomatic.org/2009/08/sheeple-mop/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 08:43:39 +0000</pubDate>
		<dc:creator>sykopomp</dc:creator>
				<category><![CDATA[random]]></category>
		<category><![CDATA[metaprogramming]]></category>
		<category><![CDATA[object-oriented programming]]></category>
		<category><![CDATA[sheeple]]></category>

		<guid isPermaLink="false">http://sykosomatic.org/blog/?p=60</guid>
		<description><![CDATA[There&#8217;s been some work done on Sheeple&#8217;s MOP, and I figured I&#8217;d write a bit about what got done today&#8230; The original reason for writing Sheeple, like I said before, was to use it with Sykosomatic (which I still haven&#8217;t written an entry for, meh). That said, Sykosomatic&#8217;s object system needs to be fully persistent. [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s been some work done on Sheeple&#8217;s MOP, and I figured I&#8217;d write a bit about what got done today&#8230;</p>
<p>The original reason for writing Sheeple, like I said before, was to use it with Sykosomatic (which I still haven&#8217;t written an entry for, meh). That said, Sykosomatic&#8217;s object system needs to be fully persistent. Sheeple itself is not persistent &#8212; it works like a standard run-time object system.</p>
<p>Because I&#8217;m a masochist and a nerd, I figured I&#8217;d simply write Sheeple as the regular object system that it is, then &#8220;just&#8221; add a Metaobject Protocol like CLOS&#8217; once the base language was set. Ho boy, did I ask for trouble. MOPs are a royal pain in the ass to do properly, and they&#8217;re a bit mind-bending. Regardless, Sheeple has been slowly getting MOP features over time. The neat part? The MOP itself is written in CLOS (as are a lot of Sheeple&#8217;s internals).</p>
<p>What I managed to get done today is the protocol for manipulating properties and property behavior through property metaobjects.<br />
<span id="more-60"></span><br />
To show how it works, let&#8217;s go over an example of how one might implement persistent-sheeple, so maybe the damn thing can actually be used for Sykosomatic&#8230;</p>
<pre>
<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_in_pkg.htm" class="symbol">in-package</a> <span class="keyword">:sheeple-user</span></span>)</span>

<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defpar.htm" class="symbol"><i><span class="symbol">defvar</span></i></a> <span class="special">*max-oid*</span> 0</span>)</span>
<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defcla.htm" class="symbol"><i><span class="symbol">defclass</span></i></a> persistent-sheep <span class="paren2">(<span class="code">standard-sheep</span>)</span>
  <span class="paren2">(<span class="code"><span class="paren3">(<span class="code">oid <span class="keyword">:initform</span> <span class="paren4">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_incf_.htm" class="symbol">incf</a> <span class="special">*max-oid*</span></span>)</span> <span class="keyword">:reader</span> oid</span>)</span></span>)</span></span>)</span>

<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defcla.htm" class="symbol"><i><span class="symbol">defclass</span></i></a> persistent-property <span class="paren2">(<span class="code">standard-property</span>)</span> <span class="paren2">(<span class="code"></span>)</span></span>)</span>
</pre>
<p>The first step to changing behavior is to make some subclasses. We&#8217;ll be dispatching on these.</p>
<pre>
<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defmet.htm" class="symbol"><i><span class="symbol">defmethod</span></i></a> <a href="http://www.lispworks.com/reference/HyperSpec/Body/f_init_i.htm" class="symbol">initialize-instance</a> <span class="keyword">:after</span> <span class="paren2">(<span class="code"><span class="paren3">(<span class="code">sheep persistent-sheep</span>)</span> &amp;key</span>)</span>
  <span class="paren2">(<span class="code">allocate-sheep-externally sheep</span>)</span></span>)</span>

<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defmet.htm" class="symbol"><i><span class="symbol">defmethod</span></i></a> add-parent <span class="keyword">:around</span> <span class="paren2">(<span class="code"><span class="paren3">(<span class="code">new-parent standard-sheep</span>)</span>
                               <span class="paren3">(<span class="code">child persistent-sheep</span>)</span></span>)</span>
  <span class="paren2">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/s_if.htm" class="symbol"><i><span class="symbol">if</span></i></a> <span class="paren3">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/a_or.htm" class="symbol">or</a> <span class="paren4">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/a_eql.htm" class="symbol">eql</a> new-parent =dolly=</span>)</span>
          <span class="paren4">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/a_eql.htm" class="symbol">eql</a> <span class="paren5">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/f_find_c.htm" class="symbol">find-class</a> 'persistent-sheep</span>)</span>
               <span class="paren5">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/f_clas_1.htm" class="symbol">class-of</a> new-parent</span>)</span></span>)</span></span>)</span>
      <span class="paren3">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/s_progn.htm" class="symbol"><i><span class="symbol">progn</span></i></a>
        <span class="paren4">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/f_call_n.htm" class="symbol">call-next-method</a></span>)</span>
        <span class="paren4">(<span class="code">add-parent-externally new-parent child</span>)</span></span>)</span>
      <span class="paren3">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/a_error.htm" class="symbol">error</a> <span class="string">"We don't support adding non-persistent~
              sheep as parents!"</span></span>)</span></span>)</span></span>)</span>
</pre>
<p>The first and most important part of having a persistent object is that it&#8217;s somehow allocated externally. All Sheeple are standard CLOS instances, so this method will get called each and every time the sheep object is created.</p>
<p>We also go ahead and write a method for <code>add-parent</code>. This is important because we want to make sure that we can successfully serialize the sheep. We must always have at -least- <code>=dolly=</code> as a parent, so we have to make an exception for that. Other than that, no non-persistent sheep are allowed into a persistent-sheep&#8217;s hierarchy list. Note that methods defined on add-parent must not override the standard behavior (basically, the <code>(standard-sheep standard-sheep)</code> method must always be called). Other than that, clients are free to go wild with what they do with this one.</p>
<p>With this much code (aside from serialization and db-management stuff!) we can now have externally-stored sheep objects. The rest of sheeple will work normally at this point. The whole point of persistent-sheeple, though, is to be able to store property values externally, so here we go&#8230; </p>
<pre>
<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defmet.htm" class="symbol"><i><span class="symbol">defmethod</span></i></a> add-property <span class="keyword">:around</span> <span class="paren2">(<span class="code"><span class="paren3">(<span class="code">sheep persistent-sheep</span>)</span> pname
                                 value &amp;key transientp</span>)</span>
  <span class="paren2">(<span class="code">register-property-externally sheep pname</span>)</span>
  <span class="paren2">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/s_if.htm" class="symbol"><i><span class="symbol">if</span></i></a> transientp
      <span class="paren3">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/f_call_n.htm" class="symbol">call-next-method</a></span>)</span>
      <span class="paren3">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/f_call_n.htm" class="symbol">call-next-method</a> sheep pname value
                        <span class="keyword">:property-metaclass</span> 'persistent-property</span>)</span></span>)</span></span>)</span>

<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defmet.htm" class="symbol"><i><span class="symbol">defmethod</span></i></a> add-property-using-property-metaobject <span class="keyword">:before</span>
    <span class="paren2">(<span class="code"><span class="paren3">(<span class="code">sheep persistent-sheep</span>)</span> value
     <span class="paren3">(<span class="code">property persistent-property</span>)</span> &amp;key</span>)</span>
  <span class="paren2">(<span class="code">allocate-property-externally sheep pname</span>)</span></span>)</span>
</pre>
<p>Because Sheeple requires that properties be specifically added to the hierarchy-list, we have these two functions: The first one takes care of creating a property metaobject for the second one to dispatch on. In this case, we make our :around method on <code>add-property</code> accept a keyword that tells it whether a property should be transient or not.</p>
<p>For the purpose of this exercise, we assume that a transient property is simply a regular property on a persistent-sheep. Since we want to make sure we&#8217;ve got the property available when we restore the database, though, we register its existence regardless of whether it&#8217;s transient or not.</p>
<p>Next up, in a-p-u-p-m, we actually dispatch on the property object itself, instead of just the class. This :before method sits there to make sure we have external DB space to allocate a value on, since we&#8217;re sure in this case that we&#8217;ll be assigning actual values to this one.</p>
<p>Once that&#8217;s set, it&#8217;s just a matter of making sure we can get/set those values, and we&#8217;re home free&#8230;</p>
<pre>
<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defmet.htm" class="symbol"><i><span class="symbol">defmethod</span></i></a> direct-property-value <span class="paren2">(<span class="code"><span class="paren3">(<span class="code">sheep persistent-sheep</span>)</span>
                                  <span class="paren3">(<span class="code">property persistent-property</span>)</span></span>)</span>
  <span class="paren2">(<span class="code">get-property-value-externally sheep <span class="paren3">(<span class="code">property-name property</span>)</span></span>)</span></span>)</span>

<span class="paren1">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/m_defmet.htm" class="symbol"><i><span class="symbol">defmethod</span></i></a> <span class="paren2">(<span class="code"><a href="http://www.lispworks.com/reference/HyperSpec/Body/a_setf.htm" class="symbol">setf</a> property-value</span>)</span> <span class="paren2">(<span class="code">new-value <span class="paren3">(<span class="code">sheep persistent-sheep</span>)</span>
                                  <span class="paren3">(<span class="code">property persistent-property</span>)</span></span>)</span>
  <span class="paren2">(<span class="code">set-property-value-externally sheep <span class="paren3">(<span class="code">property-name property</span>)</span>
                                 new-value</span>)</span></span>)</span>
</pre>
<p>And that&#8217;s it. We override the standard getting/setting behavior so nothing is set locally: Storage lives in the database.</p>
<p>Keep in mind here that a built-in :before method for <code>(setf property-value)</code> will take care of calling <code>add-property</code> as appropriate when the sheep object does not have a direct property metaobject registered for that property-name.</p>
<p>Now we can actually use it:</p>
<pre>
<span class="paren1">(<span class="code"><i><span class="symbol">defproto</span></i> =psheep= <span class="paren2">(<span class="code"></span>)</span>
  <span class="paren2">(<span class="code"><span class="paren3">(<span class="code">foo <span class="string">"bar"</span></span>)</span>
   <span class="paren3">(<span class="code">baz <span class="string">"quux"</span> <span class="keyword">:transientp</span> <a href="http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm" class="symbol">t</a></span>)</span></span>)</span>
  <span class="paren2">(<span class="code"><span class="keyword">:metaclass</span> 'persistent-sheep</span>)</span></span>)</span>
</pre>
<p>(note: <code>defproto</code> changed a bit in recent commits, more on that later&#8230;)</p>
<p>And there you have it! <code>(setf (foo =psheep=) "Blargh")</code> is all it takes to start changing stuff in your new persistent sheep. The rest of sheeple will work as expected. It&#8217;s worth noting that roles belonging to this object won&#8217;t be persisted, since we only messed around with object creation and properties.</p>
<h3>Discussion</h3>
<p>While I&#8217;m very pleased that the MOP has come this far, I have to admit that it probably doesn&#8217;t work very well right now. It&#8217;s very new, and very much still a work-in-progress. There&#8217;s probably certain things that could be cleaned up and all that, but I think it&#8217;s certainly a step in the right direction.</p>
<p>I&#8217;m honestly not entirely sure what I&#8217;m doing half the time. Even though I&#8217;ve read through AMOP several times, some of this is still a bit confusing, and I haven&#8217;t actually used CLOS&#8217; MOP very much at all. I&#8217;m playing it by ear (with a hell of a lot of help from the debugger!)</p>
<p>Hopefully, as the MOP grows (and evolves), it&#8217;ll settle into something generally useful. For now, though, YMMV if you want to mess with it.</p>
]]></content:encoded>
			<wfw:commentRss>http://sykosomatic.org/2009/08/sheeple-mop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Served from: sykosomatic.org @ 2012-05-20 04:08:47 -->
