<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Nick Sieger: Metaprogramming Pattern No. 1: Self-specialize</title>
  <id>tag:blog.nicksieger.com,2005:Typo</id>
  <generator uri="http://www.typosphere.org" version="4.0">Typo</generator>
  <link rel="self" type="application/atom+xml" href="http://blog.nicksieger.com/xml/atom10/article/33/feed.xml"/>
  <link rel="alternate" type="text/html" href="http://blog.nicksieger.com/articles/2006/07/11/metaprogramming-pattern-1-self-specialize"/>
  <updated>2007-08-31T18:02:24+00:00</updated>
  <entry>
    <author>
      <name>Nick Sieger</name>
    </author>
    <id>urn:uuid:dc66b0b8-def5-4be6-9b1e-1a2e883c6106</id>
    <published>2006-07-11T03:48:00+00:00</published>
    <updated>2007-08-31T18:02:24+00:00</updated>
    <title>Metaprogramming Pattern No. 1: Self-specialize</title>
    <link rel="alternate" type="text/html" href="http://blog.nicksieger.com/articles/2006/07/11/metaprogramming-pattern-1-self-specialize"/>
    <category term="ruby" label="ruby" scheme="http://blog.nicksieger.com/articles/category/ruby"/>
    <category term="rails" label="rails" scheme="http://blog.nicksieger.com/articles/category/rails"/>
    <category term="metaprogramming" scheme="http://blog.nicksieger.com/articles/tag/metaprogramming"/>
    <category term="pattern" scheme="http://blog.nicksieger.com/articles/tag/pattern"/>
    <content type="html">&lt;p&gt;One of the biggest aspects of Ruby that I&amp;#8217;ve been digging are the
metaprogramming facilities, many of which draw from the &amp;#8220;code as data&amp;#8221;
philosophy that comes from Lisp.  Metaprogramming has become somewhat
of a buzzword in the Ruby community, about as popular as &amp;#8220;domain
specific language&amp;#8221; in terms of its presence in the titles of
conference presentations and the like.&lt;/p&gt;

&lt;p&gt;So it seems to me that, while a good many smart people are talking and
writing about metaprogramming, that we haven&amp;#8217;t yet started cataloguing
all the different techniques in a shareable way.  Is it time to start
writing a catalog of metaprogramming patterns?  Or do I risk being
&lt;a href="http://www.c2.com/cgi/wiki?ShowTrialOfTheGangOfFour"&gt;taken to trial&lt;/a&gt; for attempting to unveil the rubyist&amp;#8217;s magic
tricks?&lt;/p&gt;

&lt;p&gt;No, what I am really looking for is the metaprogramming &lt;a href="http://domaindrivendesign.org/discussion/messageboardarchive/UbiquitousLanguage.html"&gt;ubiquitous
language&lt;/a&gt;.  Ruby has a lot of language-level features that
facilitate metaprogramming, but without a strong jargon to describe
what&amp;#8217;s going on.  Sorry, but &lt;code&gt;module_eval&lt;/code&gt;, &lt;code&gt;instance_eval&lt;/code&gt;, metaclass
vs. singleton class vs. eigenclass, &lt;code&gt;method_missing&lt;/code&gt; etc. just don&amp;#8217;t
cut it.  So here&amp;#8217;s a first shot at re-invigorating the conversation
and taking it to the &amp;#8220;HNL&amp;#8221; (&amp;#8216;hole nuther level).  So herewith begins
Metaprogramming Pattern No. 1: Self-specialize.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why is this one number 1?  No reason, pretty arbitrary.  I haven&amp;#8217;t
taken the time to document any more yet.  This will be an ongoing
project for me.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Self-specialize&lt;/h2&gt;

&lt;p&gt;You have an algorithm or a &amp;#8220;method object&amp;#8221; that you wish to make
flexible by parameterizing with additional code and/or data that isn&amp;#8217;t
known at the time you wrote the original class definition.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Therefore&lt;/em&gt;, write a method that redefines itself in the singleton
class of the currently instantiated object, then re-sends the message
to the customized method.  In a way, this is simply &lt;em&gt;memoizing&lt;/em&gt; the
method body itself as a speed-up.&lt;/p&gt;

&lt;p&gt;Trivial example:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Foo&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;p&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@prefix&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;val&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;specialize_result&lt;/span&gt;
    &lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="ident"&gt;val&lt;/span&gt; &lt;span class="comment"&gt;# send the message again&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;private&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;specialize_result&lt;/span&gt;
    &lt;span class="ident"&gt;method_decl&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;def result(val); &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="comment"&gt;#{@prefix}: #{val}&amp;quot;; end&amp;quot;&lt;/span&gt;
    &lt;span class="ident"&gt;instance_eval&lt;/span&gt; &lt;span class="ident"&gt;method_decl&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;generated code (&lt;span class="expr"&gt;#{__FILE__}&lt;/span&gt;:&lt;span class="expr"&gt;#{__LINE__}&lt;/span&gt;)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;f&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Foo&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;foo&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;hi&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; &amp;quot;foo: hi&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;g&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Foo&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;bar&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
&lt;span class="ident"&gt;g&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;hi&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; &amp;quot;bar: hi&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Why would you do this rather than writing the logic into the original
method?  It&amp;#8217;s hard to justify use of the technique in the example
above.  But it could be used to DRY up tedious, redundant code that
for performance reasons you would prefer to have inlined rather than
invoking an additional instance method.&lt;/p&gt;

&lt;p&gt;OK, so honestly I can&amp;#8217;t come up with a decent reason to do this yet; I
haven&amp;#8217;t done enough metaprogramming to have had the need for it.
Still, it seems like a nifty enough trick and maybe it will come in
handy for you.  This does show you just how dynamic Ruby&amp;#8217;s method
resolution is, that you can suddenly define and call a different
method implementation inside of the method itself!&lt;/p&gt;

&lt;p&gt;This technique was spotted in the rewritten &lt;a href="http://dev.rubyonrails.org/svn/rails/trunk/actionpack/lib/action_controller/routing.rb"&gt;routes&lt;/a&gt; implementation for
Rails 1.2 (currently on the &lt;a href="http://dev.rubyonrails.org/svn/rails/trunk/"&gt;trunk&lt;/a&gt;) &amp;#8211; see the &lt;code&gt;#write_generate&lt;/code&gt;
and &lt;code&gt;#write_recognize&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Good timing.  _why just posted &lt;a href="http://redhanded.hobix.com/inspect/methodsThatSelfDestruct.html"&gt;much more succinct description&lt;/a&gt; of the same phenomenon, with better examples.&lt;/p&gt;</content>
  </entry>
</feed>
