<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

  <title><![CDATA[Ruby is Magic – Das Blog]]></title>
  
  <link href="http://rubyismagic.de/" />
  <updated>2013-02-11T01:49:59+01:00</updated>
  <id>http://rubyismagic.de/</id>
  <author>
    <name><![CDATA[Dirk Breuer & Sebastian Cohnen]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/rubyismagic" /><feedburner:info uri="rubyismagic" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title type="html"><![CDATA[Behind the Scenes: Decorators]]></title>
    <link href="http://feedproxy.google.com/~r/rubyismagic/~3/xmeb_Hzx0yU/" />
    <updated>2012-02-09T13:27:00+01:00</updated>
    <id>http://rubyismagic.de/blog/2012/02/09/behind-the-scenes-decorators</id>
    <content type="html"><![CDATA[<p>Willkommen bei &#8220;Ruby is Magic – Behind the Scenes&#8221;. Wenn ihr euch noch
an die <a href="blog/2012/01/19/episode-7-closures/">letzte Episode</a> erinnert, dann haben wir gezeigt, wie sich in Ruby
Methoden als Closures verwenden lassen. Dazu haben wir das
<a href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator-Pattern</a> ähnlich <a href="http://stackoverflow.com/questions/101268/hidden-features-of-python#101447">wie in Python</a> <a href="https://gist.github.com/294f56ed664efa99dcac">implementiert</a>.</p>

<p>Das Transkript der letzten Show war allerdings schon recht lang und
daher sind wir nicht näher auf die Implementierung eingegangen. Da sie
jedoch sehr interessant ist, wollen wir in diesem Artikel noch einmal
im Detail darauf eingehen. Als kleinen Bonus haben wir das ganze auch
einmal einem Benchmark unterzogen – natürlich völlig
nicht-repräsentativ ;-)</p>

<!-- more -->


<p>Zunächst aber noch einmal kurz zum Hintergrund: Es ging vor
allem darum einen halbwegs realen Anwendungsfall für die Verwendung von
<code>method()</code> zu finden. Das was am Ende dann hinten raus gefallen ist,
lässt sich unserer Meinung nach sogar tatsächlich in realen
Projekten einsetzen, denn das Decorator-Pattern ermöglicht durchaus elegante
Lösungen, wenn man eine Reihe unterschiedlicher Methoden mit
zusätzlichen Funktionalitäten anreichern möchte. In unserem Beispiel war
es dann eben das Hinzufügen einer Caching-Schicht.</p>

<p>Nehmen wir als Ausgangspunkt einmal ein stark vereinfachtes Objekt, um
auf eine relationale Datenbank zuzugreifen:</p>

<figure class='code'><figcaption><span>Datenbank Anbindung ohne Caching  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">DatabaseConnector</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">find</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@connection</span><span class="o">.</span><span class="n">perform_sql</span><span class="p">(</span><span class="s2">&quot;SELECT * FROM ? WHERE id = ?&quot;</span><span class="p">,</span> <span class="nb">self</span><span class="o">.</span><span class="n">table_name</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Wir haben hier, wie so oft, unterschiedliche Möglichkeiten Caching
hinzuzufügen. Eine Variante wäre die Verwendung von <code>alias_method</code> oder
eben <code>alias_method_chain</code>, wenn ActiveSupport mit von der Partie ist. Das Ergebnis
ist, dass man eine weitere Methode in seiner Klasse definiert, die
das Caching implementiert. Dann stellen wir uns vor, dass wir noch zwei
bis drei weitere Methoden cachen wollen. Die einzelnen Implementierungen
werden dabei recht ähnlich zueinander sein und zusätzlich ist die Klasse
überladen mit Methoden, die nicht wirklich in ihren Aufgabenbereich
fallen:</p>

<figure class='code'><figcaption><span>Datenbank Anbindung mit Caching  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">DatabaseConnector</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">find</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@connection</span><span class="o">.</span><span class="n">perform_sql</span><span class="p">(</span><span class="s2">&quot;SELECT * FROM ? WHERE id = ?&quot;</span><span class="p">,</span> <span class="nb">self</span><span class="o">.</span><span class="n">table_name</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">find_with_cache</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
</span><span class='line'>    <span class="no">MyCache</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">#{</span><span class="nb">self</span><span class="o">.</span><span class="n">table_name</span><span class="si">}</span><span class="s2">-find-</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="n">find_without_cache</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>  <span class="n">alias_method_chain</span> <span class="ss">:find</span><span class="p">,</span> <span class="ss">:cache</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">count</span>
</span><span class='line'>    <span class="vi">@connection</span><span class="o">.</span><span class="n">perform_sql</span><span class="p">(</span><span class="s2">&quot;SELECT COUNT(*) FROM ?&quot;</span><span class="p">,</span> <span class="nb">self</span><span class="o">.</span><span class="n">table_name</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">count_with_cache</span>
</span><span class='line'>    <span class="no">MyCache</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">#{</span><span class="nb">self</span><span class="o">.</span><span class="n">table_name</span><span class="si">}</span><span class="s2">-count&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="n">count_without_cache</span> <span class="p">}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>  <span class="n">alias_method_chain</span> <span class="ss">:count</span><span class="p">,</span> <span class="ss">:cache</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Das erste Problem lässt sich lösen, indem die Cache-Funktionalität in
einer eigenen Klasse weiter gekapselt und diese in jeder Methode
aufgerufen wird. Realisiert man diese Klasse nun noch als Decorator,
haben wir auch das zweite Problem aus der Welt geschafft:</p>

<figure class='code'><figcaption><span>Datenbank Anbindung mit Decorator  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">CacheDecorator</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="o">*</span><span class="n">params</span><span class="p">)</span>
</span><span class='line'>    <span class="no">MyCache</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="n">cache_key</span><span class="p">(</span><span class="o">*</span><span class="n">params</span><span class="p">))</span> <span class="p">{</span>
</span><span class='line'>      <span class="vi">@component</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="o">*</span><span class="n">params</span><span class="p">)</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">DatabaseConnector</span>
</span><span class='line'>  <span class="n">decorate</span> <span class="no">CacheDecorator</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">find</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@connection</span><span class="o">.</span><span class="n">perform_sql</span><span class="p">(</span><span class="s2">&quot;SELECT * FROM ? WHERE id = ?&quot;</span><span class="p">,</span> <span class="nb">self</span><span class="o">.</span><span class="n">table_name</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Die Konstruktion des Cache-Keys ist natürlich jetzt etwas komplexer
geworden, aber irgendwas ist ja immer …</p>

<h2>Implementierung</h2>

<p>Kommen wir nun langsam zum interessanten Teil: Die Implementierung.
Vergleicht man die <code>alias_method_chain</code>-Methode mit der
Decorator-Variante, dann fallen zwei Unterschiede auf:</p>

<ol>
<li>Die Methode <code>decorate</code> wird <em>vor</em> der zu dekorierenden Methode
aufgerufen.</li>
<li>Der Name der zu dekorierenden Methode wird nicht angegeben –
lediglich die Decorator-Klasse.</li>
</ol>


<p>Überlegen wir uns zunächst einmal welche Schritte notwendig sein
werden, um unsere Decorator Funktionalität umzusetzen:</p>

<ol>
<li>Erkennen welche Methode zu dekorieren ist</li>
<li>Methode extrahieren – <code>method()</code></li>
<li>Decorator mit extrahierter Methode inititalisieren</li>
<li>Proxy Methode definieren</li>
<li>Binding vor Ausführung der “alten” Methode umsetzen</li>
</ol>


<p>Im Kontext von Closures sind nur die Punkte 2. und 5. von Relevanz. Der
Rest ist im Grunde nur Glue-Code – Was ihn jedoch nicht weniger
interessant macht.</p>

<p>Das ganze in Ruby-Code gegossen ergibt dann nicht einmal 40 Zeilen
– wieder einmal ein schönes Beispiel dafür, wie ausdrucksstark diese
Sprache ist:</p>

<figure class='code'><figcaption><span>Implementierung des Decorator-Pattern  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">FunctionDecorators</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">decorate</span><span class="p">(</span><span class="n">decorator</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@decorate_next_with</span> <span class="o">=</span> <span class="n">decorator</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">method_added</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
</span><span class='line'>    <span class="k">if</span> <span class="n">decorator_class</span> <span class="o">=</span> <span class="vi">@decorate_next_with</span>
</span><span class='line'>      <span class="vi">@decorate_next_with</span> <span class="o">=</span> <span class="kp">nil</span>
</span><span class='line'>      <span class="n">apply_decorator</span><span class="p">(</span><span class="n">decorator_class</span><span class="p">,</span> <span class="nb">name</span><span class="p">,</span> <span class="nb">self</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">__decorators</span>
</span><span class='line'>    <span class="vi">@_decorators</span> <span class="o">||=</span> <span class="p">{}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">apply_decorator</span><span class="p">(</span><span class="n">decorator</span><span class="p">,</span> <span class="n">method_name</span><span class="p">,</span> <span class="n">target</span><span class="p">)</span>
</span><span class='line'>    <span class="n">decorated_method</span> <span class="o">=</span> <span class="n">target</span><span class="o">.</span><span class="n">instance_method</span><span class="p">(</span><span class="n">method_name</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">target</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:remove_method</span><span class="p">,</span> <span class="n">method_name</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">target</span><span class="o">.</span><span class="n">__decorators</span><span class="o">[</span><span class="n">method_name</span><span class="o">]</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">:decorator</span> <span class="o">=&gt;</span> <span class="n">decorator</span><span class="o">.</span><span class="n">new</span><span class="p">,</span> <span class="ss">:method</span> <span class="o">=&gt;</span> <span class="n">decorated_method</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">new_method</span> <span class="o">=</span> <span class="o">&lt;&lt;-</span><span class="no">RUBY</span>
</span><span class='line'><span class="sh">      def #{method_name}(*params, &amp;block)</span>
</span><span class='line'><span class="sh">        unless @_#{method_name}_decorator</span>
</span><span class='line'><span class="sh">          @_#{method_name}_decorator, decorated_method = self.class.__decorators[:#{method_name}].values</span>
</span><span class='line'><span class="sh">          @_#{method_name}_decorator.bind(decorated_method, self)</span>
</span><span class='line'><span class="sh">        end</span>
</span><span class='line'>
</span><span class='line'><span class="sh">        @_#{method_name}_decorator.call(*params, &amp;block)</span>
</span><span class='line'><span class="sh">      end</span>
</span><span class='line'><span class="no">    RUBY</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">target</span><span class="o">.</span><span class="n">class_eval</span> <span class="n">new_method</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Die angesprochenen Unterschiede zu <code>alias_method</code> haben wir durch einen
der zahlreichen (und teilweise nicht dokumentierten) Callbacks in Ruby
realisiert: Der Methodenaufruf <code>decorate</code> merkt sich einfach die
Decorator-Klasse und sobald die nächste Methode definiert wird, wird
diese damit dekoriert. Auf das Hinzufügen einer Methode lässt sich dann mit
dem Callback <code>method_added</code> warten.</p>

<p>Im Callback wird dann die zu dekorierende Methode extrahiert und durch
eine neue ersetzt. Die neue Methode braucht dabei nicht die gleiche
Signatur zu besitzen (das hatten wir in der letzten Episode noch
anders) – alle Parameter einsammeln und einen optionalen Block-Parameter
definieren reicht schon aus. Auf Klassenebene legen wir unter dem
Methodennamen noch die ursprüngliche Methode und eine Instanz der
Decorator-Klasse ab. Das ist notwendig, weil wir eine <code>UnboundMethod</code>
extrahieren, d.h. sie ist keinem Objekt zugeordnet und lässt sich damit
auch nicht aufrufen. Das <code>bind</code> wird dann durchgeführt sobald die
neu-definierte Methode auf einer konkreten Instanz aufgerufen wird.
Damit erhalten wir eine Instanz von <code>Method</code>, die sich wie ein Closure
aufrufen lässt.</p>

<p>Das ganze ist als Modul realisert, welches per <code>extend</code> entweder direkt
in <code>Object</code> oder etwas selektiver nur in die zu dekorierenden Klassen
eingebunden werden kann.</p>

<p>Zur Vollständigkeit hier noch die komplette Implementierung des
<code>CacheDecorator</code>. Erwähnenswert ist noch, dass man über die <code>receiver</code>
auf der ursprünglichen Methode <code>@component</code> die die Instanz des
dekorierten Objekts erhält. Somit hat man schon hier Zugriff auf den
Kontext von <code>@component</code> und kann zum Beispiel den Cache-Key
konstruieren:</p>

<figure class='code'><figcaption><span>Implementierung des Decorators  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">CacheDecorator</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="o">*</span><span class="n">params</span><span class="p">)</span>
</span><span class='line'>    <span class="no">MyCache</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="n">cache_key</span><span class="p">(</span><span class="o">*</span><span class="n">params</span><span class="p">))</span> <span class="p">{</span>
</span><span class='line'>      <span class="vi">@component</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="o">*</span><span class="n">params</span><span class="p">)</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">cache_key</span><span class="p">(</span><span class="o">*</span><span class="n">params</span><span class="p">)</span>
</span><span class='line'>    <span class="s2">&quot;</span><span class="si">#{</span><span class="vi">@component</span><span class="o">.</span><span class="n">receiver</span><span class="o">.</span><span class="n">table_name</span><span class="si">}</span><span class="s2">-</span><span class="si">#{</span><span class="vi">@component</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">bind</span><span class="p">(</span><span class="n">component</span><span class="p">,</span> <span class="n">receiver</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@component</span> <span class="o">=</span> <span class="n">component</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">receiver</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Benchmark</h2>

<p>Wie versprochen gibt es am Ende noch einen nicht-repräsentativen
Benchmark für die Verwendung unserer Decorator-Implementierung. Wir
haben eine alternative Implementierung mit <code>alias_method_chain</code>, also
unter Verwendung von ActiveSupport mit dem Decorator-Ansatz verglichen.
Konkret sah die Teststellung wie folgt aus:</p>

<figure class='code'><figcaption><span>Benchmark  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">runs</span> <span class="o">=</span> <span class="mi">1_000_000</span>
</span><span class='line'>
</span><span class='line'><span class="no">Benchmark</span><span class="o">.</span><span class="n">bm</span><span class="p">(</span><span class="mi">40</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
</span><span class='line'>  <span class="n">x</span><span class="o">.</span><span class="n">report</span><span class="p">(</span><span class="s2">&quot;Cache with alias&quot;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">runs</span><span class="o">.</span><span class="n">times</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">connector</span> <span class="o">=</span> <span class="no">DatabaseConnectorWithAlias</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>      <span class="n">connector</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
</span><span class='line'>      <span class="n">connector</span><span class="o">.</span><span class="n">count</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">x</span><span class="o">.</span><span class="n">report</span><span class="p">(</span><span class="s2">&quot;Cache with alias (single instance)&quot;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">connector</span> <span class="o">=</span> <span class="no">DatabaseConnectorWithAlias</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>    <span class="n">runs</span><span class="o">.</span><span class="n">times</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">connector</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
</span><span class='line'>      <span class="n">connector</span><span class="o">.</span><span class="n">count</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">x</span><span class="o">.</span><span class="n">report</span><span class="p">(</span><span class="s2">&quot;Cache with Decorator&quot;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">runs</span><span class="o">.</span><span class="n">times</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">connector</span> <span class="o">=</span> <span class="no">DatabaseConnectorWithDecorator</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>      <span class="n">connector</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">23</span><span class="p">)</span>
</span><span class='line'>      <span class="n">connector</span><span class="o">.</span><span class="n">count</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">x</span><span class="o">.</span><span class="n">report</span><span class="p">(</span><span class="s2">&quot;Cache with Decorator (single instance)&quot;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">connector</span> <span class="o">=</span> <span class="no">DatabaseConnectorWithDecorator</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>    <span class="n">runs</span><span class="o">.</span><span class="n">times</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">connector</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">23</span><span class="p">)</span>
</span><span class='line'>      <span class="n">connector</span><span class="o">.</span><span class="n">count</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Wie erwartet ist die Decorator-Implementierung signifikant langsamer
als <code>alias_method_chain</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>______                                         user     system      total        real
</span><span class='line'>Cache with alias                           2.650000   0.010000   2.660000 (  2.671713)
</span><span class='line'>Cache with alias (single instance)         2.370000   0.000000   2.370000 (  2.419900)
</span><span class='line'>Cache with Decorator                      13.620000   0.020000  13.640000 ( 13.794589)
</span><span class='line'>Cache with Decorator (single instance)     8.750000   0.020000   8.770000 (  8.809148)</span></code></pre></td></tr></table></div></figure>


<p>Aber es war ja auch nicht das Ziel <code>alias_method_chain</code> zu ersetzen,
sondern einen Anwendungsfall für Methoden als Closures zu finden. Wir
denken, dass ist uns gut gelungen und wir werden diese Implementierung
definitiv irgendwo mal verwenden, denn es macht den Code durchaus
übersichtlicher und die Decorator besser testbar.</p>

<p>Das war es auch schon mit dem ersten &#8220;Behind the Scenes&#8221;. Wir hoffen es
hat auch gefallen. Wir sehen uns bei der nächsten &#8220;Ruby is Magic&#8221;-Show
am 15.02.2012 auf der <a href="http://colognerb.de">cologne.rb</a>.</p>
]]></content>
  <feedburner:origLink>http://rubyismagic.de/blog/2012/02/09/behind-the-scenes-decorators/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Episode #7: Closures]]></title>
    <link href="http://feedproxy.google.com/~r/rubyismagic/~3/wPSalozv37c/" />
    <updated>2012-01-19T22:55:00+01:00</updated>
    <id>http://rubyismagic.de/blog/2012/01/19/episode-7-closures</id>
    <content type="html"><![CDATA[<p>Herzlich willkommen zu der <del>ersten</del> siebten Ausgabe von &#8216;Ruby is Magic&#8217;. Für alle
die am 18.01. bei der <a href="http://colognerb.de">colognerb</a> nicht live mit
dabei sein konnten, oder einfach noch mal lesen wollen was passiert ist,
kommt hier nun die schriftliche Zusammenfassung mit Codestücken und
Ponies.</p>

<p>Inspiriert von einem hervorragenden <a href="http://innig.net/software/ruby/closures-in-ruby.html">Beitrag von Paul Cantrell</a>, haben wir uns
in dieser Folge einem Ruby-Thema gewidmet, dem jeder Ruby-Entwickler
regelmäßig begegnet: <em>Blöcke und Closures</em>. Wie bei vielem, dass wir
regelmäßig verwenden lohnt sich aber auch hier ein Blick hinter das
Offensichtliche. Und vielleicht entdeckt man etwas, dass einem bisher so nicht
klar war. Wir hoffen also euch neue Erkenntnisse über Closures in Ruby nahe zu
bringen – wir hatten jedenfalls welche bei den Vorbereitungen der Show.</p>

<!-- more -->


<p>Wie so oft lassen sich Eigenschaften von Programmiersprachen am besten
in der Sprache selbst verdeutlichen. Bevor wir euch aber mit
einem Code-Fragment nach dem anderen bewerfen, wollen wir kurz eine
Definition von Closures liefern. Sie erhebt dabei keinerlei Anspruch
auf Vollständigkeit, wir brauchen nur eine gemeinsame Grundlage.</p>

<p><strong>Wir verstehen Closures als Codeblöcke, die …</strong></p>

<ul>
<li>zugewiesen und herumgereicht werden können.</li>
<li>jederzeit und von jedem aufgerufen werden können.</li>
<li>Zugriff auf Variablen im ursprünglich definierenden Kontext haben.</li>
</ul>


<p>Diese Definition ist nicht exklusiv gültig für Ruby, sondern lässt sich
auch auf andere Sprachen anwenden. In Ruby zeichnen sich Closures
darüber hinaus dadurch aus, dass sie auf die Methode <code>call()</code> antworten.
Gleichzeitig ist natürlich nicht jedes Objekt, dass auf <code>call()</code>
antworten kann auch ein Closure.</p>

<h2>Die Sieben ist unsere Zahl</h2>

<p><img class="right" src="http://rubyismagic.de/images/posts/episode_7_closures/sieben.png" width="400" height="289"></p>

<p>Wirklich bemerkenswert – und durchaus auch verwirrend – ist die Fülle an
Konstrukten, die in Ruby Closures oder Closure-ähnliches beschreiben: Es
gibt derer sieben an der Zahl. Auf den ersten Blick sieht das nach einer
ganzen Menge aus, es stellt sich aber heraus, dass es am Ende dann doch
wieder einfacher ist als gedacht.</p>

<p>Jetzt tun wir aber mal endlich Butter bei die Fische und schauen uns ein
wenig Ruby-Code an. Den Anfang machen einfach <em>Blöcke</em>. Solche wie sie
wohl jeder von uns täglich im Zusammenhang mit Iteratoren verwendet:</p>

<figure class='code'><figcaption><span>Einfache Blöcke  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="vi">@my_bag</span> <span class="o">=</span> <span class="no">Bag</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>
</span><span class='line'><span class="sx">%w(MacBook Headphones iPhone Camera)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span><span class='line'>  <span class="vi">@my_bag</span><span class="o">.</span><span class="n">add</span> <span class="n">item</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Der an <code>each</code> übergebene Codeblock wird für jedes Element in dem Array
aufgerufen und hat dabei Zugriff auf den umgebenen Kontext. Dadurch
können wir mit <code>@my_bag</code> interagieren. Damit ist eines unserer
definierenden Kriterien schon mal erfüllt.</p>

<p>Angenommen wir benötigen nun eine Methode <code>each_item</code> auf der Klasse
<code>Bag</code> die es uns ermöglicht über alles zu iterieren, was jemand dort
hineingesteckt hat. Eine mögliche Implementierung könnte dann wie folgt
aussehen:</p>

<figure class='code'><figcaption><span>&#8216;each_item&#8217;-Implementierung  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Bag</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">each_item</span>
</span><span class='line'>    <span class="vi">@items</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span><span class='line'>      <span class="k">yield</span> <span class="n">item</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="vi">@my_bag</span><span class="o">.</span><span class="n">each_item</span> <span class="p">{</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span> <span class="nb">puts</span> <span class="n">item</span> <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Bemerkenswert an dieser Stelle ist, dass wir in der Methodensignatur
keine Parameter definiert haben. Blöcke können also einfach implizit an
Methoden weitergereicht werden. Gleichzeitig lässt sich der Block
dadurch auch nur implizit über das Schlüsselwort <code>yield</code> referenzieren.
Objekte, die man <code>yield</code> übergibt werden als Parameter an den Block
weiter gereicht. Falls man <code>yield</code> verwendet und keinen Block übergeben
hat, beschwert sich Ruby mit der Meldung <code>LocalJumpError: no block given (yield)</code>.
Ob ein Block übergeben wurde oder nicht, lässt sich mit der Methode <code>block_given?</code>
prüfen.</p>

<p>Blöcke fangen den definierenden Kontext zwar ein, können ihn jedoch (zum
Glück) nicht erweitern. So erhält man dann auch bei der Ausführung des
nachfolgenden Codes einen Fehler.</p>

<figure class='code'><figcaption><span>Blöcke erweitern den definierenden Kontext nicht  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="sx">%w(MacBook Headphones iPhone Camera)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span>
</span><span class='line'>  <span class="n">item_count</span> <span class="o">||=</span> <span class="mi">0</span>
</span><span class='line'>  <span class="vi">@my_bag</span><span class="o">.</span><span class="n">add</span> <span class="n">item</span>
</span><span class='line'>  <span class="n">item_count</span> <span class="o">+=</span> <span class="mi">1</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="nb">puts</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">item_count</span><span class="si">}</span><span class="s2"> item(s) have been added to my bag.&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># =&gt; NameError: undefined local variable or method ‘item_count’</span>
</span></code></pre></td></tr></table></div></figure>


<p>Insgesamt sind Blöcke also schon mal ein guter Schritt in die richtige Richtung.
Allerdings fehlen noch zwei Eigenschaften:</p>

<ul>
<li>Wir können den Block nicht beliebig herumreichen (nur einmal beim
Methodenaufruf) <em>und</em></li>
<li>Wir können den Block nicht jederzeit aufrufen.</li>
</ul>


<p>Beiden Problemen lässt sich damit begegnen, in dem man den Block
explizit macht, also in die Methodensignatur aufnimmt:</p>

<figure class='code'><figcaption><span>Expliziter Block  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Bag</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">items</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@items</span> <span class="o">=</span> <span class="n">items</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">each_item</span><span class="p">(</span><span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@items</span><span class="o">.</span><span class="n">each</span><span class="p">(</span><span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">bag</span> <span class="o">=</span> <span class="no">Bag</span><span class="o">.</span><span class="n">new</span> <span class="sx">%w(MacBook Headphones Keys)</span>
</span><span class='line'><span class="n">bag</span><span class="o">.</span><span class="n">each_item</span> <span class="p">{</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span> <span class="nb">puts</span> <span class="n">item</span> <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Als Nutzer der Methode ändert sich für mich dadurch übrigens überhaupt
nichts. Ich erhalte nicht einmal einen <code>ArgumentError</code> wenn ich den
Block nicht an die Methode übergebe – selbst nicht bei dem Aufruf von
<code>@items.each(&amp;block)</code>, denn <code>each</code> liefert einfach eine
<code>Enumerator</code>-Instanz zurück, wenn kein Block mitgegeben wird.</p>

<p>Als letzten Schritt müssen wir nun nur noch dafür sorgen, dass der Block
gespeichert werden kann und somit jederzeit aufrufbar wird. Wir
erreichen das, indem wir uns einfach das <code>&amp;</code>-Prefix des Blockparameters
sparen, was ein Synonym für <code>Proc.new(&amp;block)</code> ist.</p>

<figure class='code'><figcaption><span>Speichern des Blocks  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Bag</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">items</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@items</span> <span class="o">=</span> <span class="n">items</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">define_iterator</span><span class="p">(</span><span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@iterator</span> <span class="o">=</span> <span class="n">block</span> <span class="c1"># Proc.new &amp;block</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">iterate!</span>
</span><span class='line'>    <span class="vi">@items</span><span class="o">.</span><span class="n">each</span><span class="p">(</span><span class="o">&amp;</span><span class="vi">@iterator</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">bag</span> <span class="o">=</span> <span class="no">Bag</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="sx">%w(MacBook Headphones Keys)</span><span class="p">)</span>
</span><span class='line'><span class="n">bag</span><span class="o">.</span><span class="n">define_iterator</span> <span class="p">{</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span> <span class="nb">puts</span> <span class="n">item</span> <span class="p">}</span>
</span><span class='line'><span class="n">bag</span><span class="o">.</span><span class="n">iterate!</span>
</span></code></pre></td></tr></table></div></figure>


<p>Damit haben wir also endlich unser Closure. Wir hoffen es hat euch mal
wieder gefallen und bis zum nächsten Mal … Moment! … Das kann es doch
noch nicht gewesen sein. Richtig – da kommt noch was!</p>

<h2>&#8220;Echte&#8221; Closures?!</h2>

<p>Wie Eingangs bereits erwähnt, hält Ruby für uns mehrere Möglichkeiten
bereit ein Closure zu konstruieren:</p>

<ul>
<li><code>&amp;block</code> ohne <code>&amp;</code> ist wie <code>Proc.new(&amp;block)</code></li>
<li><code>proc {}</code></li>
<li><code>lambda {}</code></li>
</ul>


<p>Die Variante mit <code>proc</code> ist übrigens noch keinem von uns bewusst in der
freien Wildbahn aufgefallen und es handelt sich dabei auch lediglich um
ein Alias auf <code>lambda</code>. Was irgendwie nicht besonders intuitiv ist. Das
hat sich dann wohl auch das Ruby-Core-Team gedacht und ab Ruby 1.9 ist
<code>proc</code> sinniger Weise ein Alias auf <code>Proc.new</code>.</p>

<p>Dennoch stellt sich die Frage, ob Unterschiede zwischen den <code>lambda</code> und
<code>Proc.new</code> Varianten existieren? Und wenn ja, welche? Die Antwort ist zu
erwarten gewesen: Ja, es gibt Unterschiede. Schauen wir uns einmal den <em>Kontrollfluss</em> und die <em>Prüfung der Arität</em> an.</p>

<h3>Kontrollfluss</h3>

<p>Wenn man innerhalb eines Closures oder Code-Blocks <code>return</code> verwenden
möchte führt dies unter Umständen nicht immer zu dem gewünschten
Resultat:</p>

<figure class='code'><figcaption><span>Unterschiedliches Verhalten bei &#8216;return&#8217;  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">call_closure</span><span class="p">(</span><span class="n">closure</span><span class="p">)</span>
</span><span class='line'>  <span class="nb">puts</span> <span class="s2">&quot;Calling a closure&quot;</span>
</span><span class='line'>  <span class="n">result</span> <span class="o">=</span> <span class="n">closure</span><span class="o">.</span><span class="n">call</span>
</span><span class='line'>  <span class="nb">puts</span> <span class="s2">&quot;The result of the call was: </span><span class="si">#{</span><span class="n">result</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">call_closure</span><span class="p">(</span><span class="no">Proc</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="k">return</span> <span class="s2">&quot;All hell breaks loose!&quot;</span> <span class="p">})</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># =&gt; Calling a closure</span>
</span><span class='line'><span class="c1"># =&gt; LocalJumpError: unexpected return</span>
</span><span class='line'>
</span><span class='line'><span class="n">call_closure</span><span class="p">(</span><span class="nb">lambda</span> <span class="p">{</span> <span class="k">return</span> <span class="s2">&quot;Everypony calm down. All is good.&quot;</span> <span class="p">})</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># =&gt; Calling a closure</span>
</span><span class='line'><span class="c1"># =&gt; The result of the call was: ‘Everypony calm down. All is good.’</span>
</span></code></pre></td></tr></table></div></figure>


<p>Während sich also ein <code>return</code> in einem durch <code>Proc.new</code> erzeugten
Closure immer auf den ursprünglich definierenden Kontext bezieht (in diesem Beispiel ist das <code>main</code>), springt es in einem <code>lambda</code>-Closure einfach aus dem <code>lambda</code> zurück. Bei der Verwendung der <code>lambda</code>-Methode erhält man also eine &#8220;true closure&#8221;, welches sich in puncto Kontrollfluss wie eine Methode verhält. In beiden Fällen erhält man übrigens eine Instanz der <code>Proc</code>-Klasse.</p>

<h3>Aritätsprüfung</h3>

<p>Closures antworten nicht nur auf <code>call()</code>, sondern auch auf die Nachricht
<code>arity()</code>:</p>

<blockquote><p>Returns the number of arguments that would not be ignored. If the block<br/>is declared to take no arguments, returns 0. If the block is known to<br/>take exactly n arguments, returns n. If the block has optional<br/>arguments, return -n-1, where n is the number of mandatory arguments. A<br/>proc with no argument declarations is the same a block declaring || as<br/>its arguments.</p><footer><strong>Ruby-Dokumentation</strong> <cite><a href='http://www.ruby-doc.org/core-1.9.3/Proc.html#method-i-arity'>www.ruby-doc.org/core-1.9.3/&hellip;</a></cite></footer></blockquote>


<p>Es liegt nahe, dass die Arität beim Aufruf des Closures überprüft wird.
Falls die Anzahl der Parameter dann nicht mit der erwarteten
übereinstimmt wird ein <code>ArgumentError</code> geworfen. Dieses Verhalten tritt
allerdings nur auf, wenn die <code>lambda</code>-Methode verwendet wurde.
&#8220;Closures&#8221; durch <code>Proc.new</code> überprüfen die Arität nicht:</p>

<figure class='code'><figcaption><span>Aritätsprüfung: Proc.new  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">proc_closure</span> <span class="o">=</span> <span class="no">Proc</span><span class="o">.</span><span class="n">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="o">|</span>
</span><span class='line'>  <span class="nb">puts</span> <span class="s2">&quot;arg1: </span><span class="si">#{</span><span class="n">arg1</span><span class="si">}</span><span class="s2">; arg2: </span><span class="si">#{</span><span class="n">arg2</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">proc_closure</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">)</span> <span class="c1"># arg1: 1; arg2: 2</span>
</span><span class='line'><span class="n">proc_closure</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># arg1: 1; arg2: 2</span>
</span><span class='line'><span class="n">proc_closure</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># arg1: 1; arg2: nil</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>Aritätsprüfung: lambda  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">lambda_closure</span> <span class="o">=</span> <span class="nb">lambda</span> <span class="k">do</span> <span class="o">|</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="o">|</span>
</span><span class='line'>  <span class="nb">puts</span> <span class="s2">&quot;arg1: </span><span class="si">#{</span><span class="n">arg1</span><span class="si">}</span><span class="s2">; arg2: </span><span class="si">#{</span><span class="n">arg2</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">lambda_closure</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">)</span> <span class="c1"># ArgumentError</span>
</span><span class='line'><span class="n">lambda_closure</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># arg1: 1; arg2: 2</span>
</span><span class='line'><span class="n">lambda_closure</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># ArgumentError</span>
</span></code></pre></td></tr></table></div></figure>


<p>Aber genauso magisch wie Ruby ist, gibt ist auch immer mal wieder
<a href="https://www.destroyallsoftware.com/talks/wat">Momente der Verwirrung</a>.
So auch in diesem Fall: Closures aus <code>lambda</code> prüfen die Arität nur in
Ruby 1.9 so wie erwartet. Und damit kommen wir dann auch zum <strong>Fun Fact</strong>
dieser Ausgabe:</p>

<p>In Ruby 1.8 gilt für Closures durch <code>lambda</code>:</p>

<ul>
<li><code>lambda {||}.arity != lambda {}.arity</code></li>
<li><code>lambda {}.arity == -1</code></li>
<li>Die Anzahl der Argumente wird nicht geprüft wenn die Arität 1 ist</li>
</ul>


<p>In Ruby 1.9 ist die Welt aber wie gesagt in Ordnung, zumindest in dieser
Hinsicht: <code>lambda {}.arity == lambda {||}.arity == 0</code></p>

<p>Dirk hat ein nettes Beispiel für Closures in seinem Blog vor einiger Zeit geschrieben: <a href="http://railsbros.de/2011/04/09/lazy_load_collection.html">Roll your own lazy loading collection</a> beschreibt, wie man eine <em>lazy collection</em> bauen kann.</p>

<h2>One More Thing</h2>

<p><img class="right" src="http://rubyismagic.de/images/ponies/pinkie_pie.png" width="280" height="311"></p>

<p>Fassen wir einmal zusammen, welche Möglichkeiten von Closures wir bisher besprochen haben:</p>

<ul>
<li>block (implizit übergeben)</li>
<li>block (explizit übergeben)</li>
<li>block (explizit übergeben und zu Proc)</li>
<li><code>Proc.new</code></li>
<li><code>proc</code> (Alias auf <code>lambda</code> / <code>Proc.new</code>)</li>
<li><code>lambda</code></li>
</ul>


<p>Aber fehlt da nicht noch etwas? JA!</p>

<p>Methoden sind ebenfalls Closures! Das sie den umgebenen Kontext einfangen ist offensichtlich. Sie überprüfen weiterhin die Arität und ein <code>return</code> springt nur aus der Methode heraus.</p>

<p>Um eine Methode referenzierbar zu machen, benötigt man die <code>method()</code>-Methode. Mit <code>method()</code> erhält man eine <code>Method</code>-Instanz, welches die Methode repräsentiert.</p>

<figure class='code'><figcaption><span>Methoden als Closures  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Bag</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">each_item</span><span class="p">(</span><span class="n">closure</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@items</span><span class="o">.</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span> <span class="n">closure</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">Iterator</span>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">print_element</span><span class="p">(</span><span class="n">element</span><span class="p">)</span>
</span><span class='line'>    <span class="nb">puts</span> <span class="s2">&quot;Element: </span><span class="si">#{</span><span class="n">element</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">my_bag</span> <span class="o">=</span> <span class="no">Bag</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="sx">%w(MacBook Headphones iPad Gloves)</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="n">my_bag</span><span class="o">.</span><span class="n">each_item</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">item</span><span class="o">|</span> <span class="nb">puts</span> <span class="s2">&quot;Element: </span><span class="si">#{</span><span class="n">item</span><span class="si">}</span><span class="s2">&quot;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">my_bag</span><span class="o">.</span><span class="n">each_item</span> <span class="no">Iterator</span><span class="o">.</span><span class="n">method</span><span class="p">(</span><span class="ss">:print_element</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>Als Beispiel für Methoden als Closures haben wird eine Implementierung von
<a href="http://stackoverflow.com/questions/101268/hidden-features-of-python#101447">Python-style Decorators</a> gezeigt.
Den Code dazu findet ihr <a href="https://gist.github.com/294f56ed664efa99dcac">hier</a> und ein paar weitere Details wird es in einem separatem Post geben.</p>

<h2>Präsentation</h2>

<p>Und hier noch die Präsentation. Für das volle audio-visuelle Erlebnis
müsst ihr allerdings zur <a href="http://twitter.com/colognerb">@colognerb</a> kommen ;-)</p>

<div style="width:595px;margin:auto" id="__ss_11190532"> <object id="__sse11190532" width="595" height="497"> <param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=colognerb-closures-120121083720-phpapp02&rel=0&stripped_title=ruby-is-magic-episode-7-closures&userName=railsbros_dirk" /> <param name="allowFullScreen" value="true"/> <param name="allowScriptAccess" value="always"/> <param name="wmode" value="transparent"/> <embed name="__sse11190532" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=colognerb-closures-120121083720-phpapp02&rel=0&stripped_title=ruby-is-magic-episode-7-closures&userName=railsbros_dirk" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="transparent" width="595" height="497"></embed> </object> </div>

]]></content>
  <feedburner:origLink>http://rubyismagic.de/blog/2012/01/19/episode-7-closures/</feedburner:origLink></entry>
  
</feed>
