<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Tom Moertel's Weblog: Tag closures</title>
    <link>http://blog.moertel.com/articles/tag/closures?tag=closures</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Quality rants on programming theory and stuff geeks like</description>
    <item>
      <title>Closures and the professional programmer</title>
      <description>&lt;p&gt;I came across &lt;a href="http://www.tbray.org/ongoing/When/200x/2005/08/27/Ruby"&gt;Tim Bray&amp;#8217;s thoughts on
Ruby&lt;/a&gt; via
the ever-delightful &lt;a href="http://lambda-the-ultimate.org/node/view/934"&gt;Lambda the Ultimate&lt;/a&gt; and found the following bit fascinating:&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;I&amp;#8217;ve had access to languages with closures and continuations and
suchlike constructs for years and years, and I&amp;#8217;ve never ever written
one. While I&amp;#8217;m impressed by how natural this stuff is in Ruby, &lt;em&gt;I&amp;#8217;m
still unconvinced that these are a necessary part of the professional
programmer&amp;#8217;s arsenal.&lt;/em&gt; [Emphasis mine.]&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;While Tim Bray may be unconvinced, I am a true believer.&lt;/p&gt;&lt;p&gt;I use closures so much that I feel cheated into doing busy work by
languages that do not support them.  I use continuations less often
but frequently enough to appreciate how much time they save me.
Neither is strictly required for professional work, but they are
potent tools, and a professional who knows how to use them has an
advantage over those who do not.&lt;/p&gt;


	&lt;p&gt;Closures, in particular, are something every professional ought to
master.  Besides their more celebrated uses, closures make refactoring practical on a small scale.  For
example, consider the following Ruby method, which we will assume is
one of several similar methods belonging to a class that implements some kind of Internet server:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;process&lt;/span&gt;
  &lt;span class="ident"&gt;sn&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;next_serial&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;process/&lt;span class="expr"&gt;#{sn}&lt;/span&gt;: stage 1&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="comment"&gt;# ... do some work&lt;/span&gt;
  &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;process/&lt;span class="expr"&gt;#{sn}&lt;/span&gt;: stage 2&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="comment"&gt;# ... do some more work&lt;/span&gt;
  &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;process/&lt;span class="expr"&gt;#{sn}&lt;/span&gt;: finished&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The method first gets a unique serial number, which is used during the processing of requests and also to relate log entries generated by the same processing call.  Then the method does its work, logging each stage in passing.&lt;/p&gt;


	&lt;p&gt;The method makes three logging calls that each hardcode the logger, the logging level, and the format of the log entries.  Since these things are repetitive and could very well change, we probably ought to factor them out into an isolated method.  After all, we don&amp;#8217;t want to rewrite a bucket of logging calls if the log-entry format changes.&lt;/p&gt;


	&lt;p&gt;Let&amp;#8217;s introduce a helper method &lt;em&gt;mylog&lt;/em&gt; to hold the common pieces:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;process&lt;/span&gt;
  &lt;span class="ident"&gt;sn&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;next_serial&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="ident"&gt;mylog&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;process&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;sn&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;stage 1&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
  &lt;span class="comment"&gt;# ... do some work&lt;/span&gt;
  &lt;span class="ident"&gt;mylog&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;process&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;sn&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;stage 2&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
  &lt;span class="comment"&gt;# ... do some more work&lt;/span&gt;
  &lt;span class="ident"&gt;mylog&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;process&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;sn&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;finished&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;def &lt;/span&gt;&lt;span class="method"&gt;mylog&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;activity&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sn&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;msg&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{activity}&lt;/span&gt;/&lt;span class="expr"&gt;#{sn}&lt;/span&gt; &lt;span class="expr"&gt;#{msg}&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;While we managed to isolate the logger, the logging level, and the
format of our logging messages, just &lt;em&gt;calling&lt;/em&gt; our helper method &lt;em&gt;mylog&lt;/em&gt; still
requires much redundancy.  Worse, the redundancy is on such a low
level that we can&amp;#8217;t factor it out with another helper method &amp;#8211; calling
the new helper would be as expensive and redundant as calling &lt;em&gt;mylog&lt;/em&gt;
directly.&lt;/p&gt;


	&lt;p&gt;What we need are refactoring tools that scale down to this sub-method level, and
that&amp;#8217;s where closures come to the rescue.  Using them, we can corral
the remaining redundancy with a local logging helper &lt;em&gt;llog&lt;/em&gt; that &amp;#8220;closes
over&amp;#8221; the relevant state:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;process&lt;/span&gt;
  &lt;span class="ident"&gt;sn&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;next_serial&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="ident"&gt;llog&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;lambda&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;mylog&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;process&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;sn&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="ident"&gt;llog&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;stage 1&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;
  &lt;span class="comment"&gt;# ... do some work&lt;/span&gt;
  &lt;span class="ident"&gt;llog&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;stage 2&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;
  &lt;span class="comment"&gt;# ... do some more work&lt;/span&gt;
  &lt;span class="ident"&gt;llog&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;finished&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Notice how much simpler and less redundant the logging code is?  Each stage can now be logged just by giving its name to &lt;em&gt;llog&lt;/em&gt;.  We don&amp;#8217;t need to pass in the activity name or serial number because &lt;em&gt;llog&lt;/em&gt; already knows them both.  It knows the activity name because we made it part of &lt;em&gt;llog&lt;/em&gt;&amp;#8217;s definition, but it knows the serial number because &lt;em&gt;sn&lt;/em&gt; is captured in &lt;em&gt;llog&lt;/em&gt;&amp;#8217;s closure &amp;#8211; for free.  (Note: If &lt;em&gt;f&lt;/em&gt; is a &lt;tt&gt;Proc&lt;/tt&gt; object, &lt;em&gt;f&lt;/em&gt;[&lt;em&gt;args&lt;/em&gt;] is syntactic sugar for &lt;em&gt;f&lt;/em&gt;&lt;tt&gt;.call&lt;/tt&gt;(&lt;em&gt;args&lt;/em&gt;).)&lt;/p&gt;


	&lt;p&gt;Of course, if we have several methods that require a unique serial
number and a corresponding logger, we could (thanks to closures)
factor things further:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;process&lt;/span&gt;
  &lt;span class="ident"&gt;sn&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;llog&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;next_serial_and_logger&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;process&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
  &lt;span class="ident"&gt;llog&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;stage 1&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;
  &lt;span class="comment"&gt;# ... do some work&lt;/span&gt;
  &lt;span class="ident"&gt;llog&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;stage 2&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;
  &lt;span class="comment"&gt;# ... do some more work&lt;/span&gt;
  &lt;span class="ident"&gt;llog&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;finished&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;def &lt;/span&gt;&lt;span class="method"&gt;next_serial_and_logger&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;activity&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;sn&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;next_serial&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;sn&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;lambda&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;mylog&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;activity&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sn&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}]&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;You get the point: Closures reduce the cost of working with local
state because they capture it implicitly.  There is no need to pass
the state back and forth; it&amp;#8217;s simply there.&lt;/p&gt;


	&lt;p&gt;Because the craft of programming is dominated by writing the stuff
&lt;em&gt;inside&lt;/em&gt; of methods, where local state lives, the potential benefits
of closures are immense.  If more programmers knew how to use them,
the profession would be richer for it.&lt;/p&gt;


&lt;div class="update"&gt;
&lt;p&gt;&lt;strong&gt;Update 2006-01-11:&lt;/strong&gt; First, because this article is getting renewed interest, I have turned the comments back on. Second, I edited the article to improve clarity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2007-05-04:&lt;/strong&gt; Added syntax highlighting to code snippets.&lt;/p&gt;
&lt;/div&gt;</description>
      <pubDate>Tue, 30 Aug 2005 14:56:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:4433a298ab264c9e20e1d5853ee5b250</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2005/08/30/closures-and-the-professional-programmer</link>
      <category>programming</category>
      <category>functional programming</category>
      <category>programming languages</category>
      <category>ruby</category>
      <category>ruby</category>
      <category>programming</category>
      <category>closures</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/3</trackback:ping>
    </item>
  </channel>
</rss>
