<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Memerocket</title>
    <description>Bill Burcham's launch platform.
</description>
    <link>http://memerocket.com/</link>
    <atom:link href="http://memerocket.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 27 Feb 2021 19:48:24 +0000</pubDate>
    <lastBuildDate>Sat, 27 Feb 2021 19:48:24 +0000</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>Use Java Lambdas Instead of Method Refs Sometimes</title>
        <description>&lt;p&gt;Java 8 method references are super useful in expressions like these:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nc&quot;&gt;Comparator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;comparing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;Person:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getLastName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CASE_INSENSITIVE_ORDER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Comparator.comparing&lt;/code&gt; is a generic method. Here’s its signature:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Comparator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;comparing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,?&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keyExtractor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;nc&quot;&gt;Comparator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keyComparator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;comparing()&lt;/code&gt;, the first parameter (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keyExtractor&lt;/code&gt;) can be provided
in one of three ways:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;a method reference (as shown in our example)&lt;/li&gt;
  &lt;li&gt;a reference to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function&lt;/code&gt; object&lt;/li&gt;
  &lt;li&gt;a lambda expression&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Which alternatives you &lt;em&gt;may&lt;/em&gt; use depends on the situation. Depending on the
situation, the compiler will either use the expected return
type&lt;a href=&quot;#[1]&quot;&gt;&lt;sup&gt;&lt;strong&gt;[1]&lt;/strong&gt;&lt;/sup&gt;&lt;/a&gt; (of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;comparing()&lt;/code&gt;) to determine the type of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keyExtractor&lt;/code&gt;, or it will use the type of the first parameter to determine the
return type. In the latter case either a method reference or a reference to a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function&lt;/code&gt; object is required, since a lambda, in general might not carry
sufficient type information.&lt;/p&gt;

&lt;p&gt;Method references are also often seen when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map()&lt;/code&gt;ing, either over streams,
or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Optional&lt;/code&gt;s like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nc&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Speaker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speaker&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AdmiralStockdale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speaker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;Speaker:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speak&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;On the second line, though, the compiler knows the type of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speaker&lt;/code&gt;, so it
knows the type of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map()&lt;/code&gt; parameter. Here’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map()&lt;/code&gt;’s signature:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,?&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;U&lt;/code&gt; is known from the declaration of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speaker&lt;/code&gt;. The type information carried
by the method reference &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Speaker::speak&lt;/code&gt; isn’t actually needed in this case.&lt;/p&gt;

&lt;p&gt;Not only is it not needed, it represents a minor but annoying maintenance trap.
By explicitly specifying the type of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speaker&lt;/code&gt; and also explicitly specifying
the type of the first argument to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map()&lt;/code&gt; we’ve set them in opposition when they
needn’t be. Sure, the compiler will tell if some future code change causes them
to be incompatible (say if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speak()&lt;/code&gt; method moves to another class or
interface), but wouldn’t it be better if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map()&lt;/code&gt; expression was decoupled
entirely from the name of that class or interface?&lt;/p&gt;

&lt;p&gt;Since the compiler doesn’t need that extra type information, and since we pay a
price in maintainability by including the extra type information, it’d be nice
if we had another way to specify the method to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How about a trivial lambda:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;speaker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;speak&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This code is shorter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s-&amp;gt;s.speak()&lt;/code&gt; versus &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Speaker::speak&lt;/code&gt;. It also has the
advantage of not tightly coupling the expression to the interface name.
By efficiently leveraging type inference, we’ve improved our code.&lt;/p&gt;

&lt;p&gt;Here’s a little Github repo with the Java code:
&lt;a href=&quot;https://github.com/Bill/lambdavsmethodref&quot;&gt;Lambda vs Method Reference on Bill’s Github&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;In Java 8, functional interfaces, method references, and lambda expressions
provide wonderful new opportunities to create higher-order functions. In some
situations, though, a method reference, by saying too much, presents a little
maintenance trap that can be avoided via a trivial lambda expression.&lt;/p&gt;

&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;
&lt;p&gt;&lt;a name=&quot;[1]&quot;&gt;[1]&lt;/a&gt; This is called the “target type” in
&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html&quot;&gt;Java type inference parlance&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Sat, 27 May 2017 15:59:16 +0000</pubDate>
        <link>http://memerocket.com/2017/05/27/java-use-lambdas-over-method-refs-sometimes</link>
        <guid isPermaLink="true">http://memerocket.com/2017/05/27/java-use-lambdas-over-method-refs-sometimes</guid>
        
        
        <category>Java</category>
        
        <category>Optional</category>
        
        <category>Streams</category>
        
        <category>Functional Programming</category>
        
      </item>
    
      <item>
        <title>These Are Not the K Combinators You Are Looking For</title>
        <description>&lt;p&gt;Since version 1.9, Ruby has had &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#tap&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tap&lt;/code&gt; started life as Rails
ActiveSupport &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#returning&lt;/code&gt;. Here’s the old Rails source code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   def foo&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     returning values = [] do&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       values &amp;lt;&amp;lt; 'bar'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       values &amp;lt;&amp;lt; 'baz'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   foo # =&amp;gt; ['bar', 'baz']&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   def foo&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     returning [] do |values|&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       values &amp;lt;&amp;lt; 'bar'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       values &amp;lt;&amp;lt; 'baz'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   foo # =&amp;gt; ['bar', 'baz']&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;returning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;returning&lt;/code&gt; an object and a block and it returns the object, after running the block on that object. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#tap&lt;/code&gt; is a slight variation on this theme&lt;a href=&quot;#[1]&quot;&gt;&lt;sup&gt;&lt;strong&gt;[1]&lt;/strong&gt;&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Clojure has a similar function called &lt;a href=&quot;https://clojuredocs.org/clojure.core/doto&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt;&lt;/a&gt; that generalizes the idea. Here’s an example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;c1&quot;&gt;;; Note that even though println returns nil, doto still returns the HashMap object&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doto&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;java.util.HashMap.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.put&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.put&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;&amp;lt;HashMap&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b=2,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a=1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The comment in the Ruby on Rails code and Jamis Buck’s, 2006 &lt;a href=&quot;http://weblog.jamisbuck.org/2006/10/27/mining-activesupport-object-returning&quot;&gt;Mining ActiveSupport: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#returning&lt;/code&gt;&lt;/a&gt; refer to this functionality as an example of the K combinator. Though &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;returning&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt; are useful, and they can really improve your (object-oriented, side-effect-dependent) code by making your intentions plain, they are not examples of the K combinator.&lt;/p&gt;

&lt;p&gt;Contrary to Buck’s analysis, a K combinator is not really a “function of two arguments”. Well, in a &lt;a href=&quot;https://wiki.haskell.org/Currying&quot;&gt;curried language like Haskell&lt;/a&gt;, it &lt;em&gt;is&lt;/em&gt; usable as a function of two arguments. But the way that (potentially) two-argument function is almost always used, is as a one-argument function that produces a function. Dig Haskell’s &lt;a href=&quot;http://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude.html#v:const&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt;&lt;/a&gt;, an actual K combinator:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Indeed you see what is potentially a two argument function. But the way &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; will be used is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;See what happened there? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const 42&lt;/code&gt; produces a function, which, when passed any parameter, e.g. 0, 1, 2, or 3, will just return 42.&lt;/p&gt;

&lt;p&gt;Similarly, Clojure has &lt;a href=&quot;https://clojuredocs.org/clojure.core/constantly&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(constantly x)&lt;/code&gt;&lt;/a&gt; that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Returns a function that takes any number of arguments and returns x.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are K combinators.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#returning&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt; are certainly higher-order functions (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt; actually happens to be a macro) in that they take a “function” as a parameter. In the case of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#returning&lt;/code&gt; the “function” is a block. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt; is a bit more general in that it takes one or more forms, not merely functions.&lt;/p&gt;

&lt;p&gt;But neither &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#returning&lt;/code&gt; nor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt;, in general, &lt;em&gt;return&lt;/em&gt; a function. Contrast this with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constantly&lt;/code&gt;, both of which return functions.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Ruby on Rails’ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#returning&lt;/code&gt;, Ruby 1.9’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#tap&lt;/code&gt;, and Clojure’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt; are useful for clearly delineating code whose only purpose is to introduce side-effects on or about some target object. Examples include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;tracing for debugging&lt;/li&gt;
  &lt;li&gt;multi-step object initialization through setters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are higher-order functions in that they each take a functional argument (or in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt;’s case, one or more). None of them, however, in general, produces a function.&lt;/p&gt;

&lt;p&gt;The K combinator, as exemplified by Haskell’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; and Clojure’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constantly&lt;/code&gt;, is useful in cases where you need to succinctly construct a function that, irrespective of its argument(s), always returns the same value. A K combinator is a higher-order function that &lt;em&gt;produces&lt;/em&gt; a function.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#returning&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#tap&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doto&lt;/code&gt; are not K combinators. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constantly&lt;/code&gt; are. These are two useful, but distinct, concepts.&lt;/p&gt;

&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;[1]&quot;&gt;[1]&lt;/a&gt; Whereas &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;returning&lt;/code&gt; yields its first parameter to the
block, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tap&lt;/code&gt; yields &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self&lt;/code&gt; and so it only needs a block parameter.&lt;/p&gt;
</description>
        <pubDate>Thu, 25 May 2017 13:57:46 +0000</pubDate>
        <link>http://memerocket.com/2017/05/25/these-are-not-the-k-combinators-you-are-looking-for</link>
        <guid isPermaLink="true">http://memerocket.com/2017/05/25/these-are-not-the-k-combinators-you-are-looking-for</guid>
        
        
        <category>Ruby</category>
        
        <category>Functional Programming</category>
        
        <category>Clojure</category>
        
        <category>Haskell</category>
        
        <category>Combinatory Logic</category>
        
        <category>Rails</category>
        
      </item>
    
      <item>
        <title>Hamstar Transforms Immutable Ruby Collections Better</title>
        <description>&lt;p&gt;When working with Amazon’s &lt;a href=&quot;http://docs.aws.amazon.com/sdkforruby/api/index.html&quot;&gt;AWS SDK for Ruby&lt;/a&gt; there are two flavors of API. The most mature parts of AWS have what’s called a &lt;a href=&quot;http://docs.aws.amazon.com/sdkforruby/api/index.html#Resource_Interfaces__aws-sdk-resources_gem_&quot;&gt;resource interface&lt;/a&gt;. These are fine-grained object-oriented interfaces to AWS objects. Want to delete a bunch of objects having the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp-files/&lt;/code&gt; path in an S3 bucket? Easy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;prefix: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/tmp-files/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s a convenient way to deal with S3 buckets. Alas vast swaths of the AWS service-space have no such convenient interface. Those services offer only a thin veneer over the underlying REST interface via a client object. A prime example of a service offering this more primitive interface is the &lt;a href=&quot;http://docs.aws.amazon.com/sdkforruby/api/Aws/ECS.html&quot;&gt;EC2 Container Service&lt;/a&gt; or ECS.&lt;/p&gt;

&lt;p&gt;If you want to say, change the version of a Docker image, referenced within an ECS task definition, the process is:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;describe_task_definition&lt;/code&gt; to retrieve the structure&lt;/li&gt;
  &lt;li&gt;pluck the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;container_definitions&lt;/code&gt; array from the structure and modify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image&lt;/code&gt; value for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;container&lt;/code&gt; of interest&lt;/li&gt;
  &lt;li&gt;call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;register_task_definition&lt;/code&gt;, passing the doctored container array&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ruby is pretty good at this sort of thing. At step 2, you just mutate the structure retrieved in step 1. At step 3 you submit part of the mutated structure back to AWS.&lt;/p&gt;

&lt;p&gt;If you’ve spent any time programming in Haskell or Clojure though, you may be hankering for a more “functional” solution. Do you really have to mutate that big complex structure? What if later you found that you needed two different versions of the structure, with two different mutations? Would you retrieve the structure from AWS twice? Or would you think about “deep cloning” the structure each time? That way lies madness.&lt;/p&gt;

&lt;p&gt;First, we’ll take a look at how we would usually approach this in Ruby, then we’ll look at how a Clojurist might think about the problem, and finally we’ll apply a more functional appproach to our Ruby solution. In the process we may even do Clojure one better!&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;

&lt;p&gt;The AWS ECS client returns a structure something like this from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;describe_task_definition&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;task_definition: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;task_definition_arn: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'some-arn-string'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;container_definitions: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'front'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;image: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'nginx:1.7'&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'my-python-web-app'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;image: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'my-python-web-app:latest'&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now there is a lot more stucture in the actual response. I’m just showing the parts that are essential for our discussion.&lt;/p&gt;

&lt;p&gt;What I’d like to do is upgrade the NGINX Docker image used by the container named “front”, to version 1.9. Note that in my upgrade script, I don’t know what version of nginx is currently in place, nor do I want to upgrade every reference to the NGINX image. I only want to upgrade ‘front’ to NGINX version 1.9.&lt;/p&gt;

&lt;p&gt;Here’s some typical Ruby to do the job:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'nginx:1.9'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'front'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now our response object can be submitted back to the server. But what if we didn’t want to mutate the original (deep) structure? Let’s just do a plain old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clone&lt;/code&gt; of that object and see what we get:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;clone&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__id__&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2155921900&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__id__&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2161504860&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So far, so good: we’ve made a copy of the response object! But wait:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__id__&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2155921940&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__id__&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2155921940&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;While the top-level Hash has been cloned, the internal values have not. This was not a deep clone.&lt;/p&gt;

&lt;p&gt;You may want to take a moment now to follow the rabbit down the hole of deep cloning Ruby objects. Or you may want to go shave your yak. I’ve been down that hole and I’ve spent time with the yak and I believe there is a better way.&lt;/p&gt;

&lt;h2 id=&quot;forget-deep-cloning-use-hamsters-immutable-collections-instead&quot;&gt;Forget Deep Cloning: Use Hamster’s Immutable Collections Instead&lt;/h2&gt;

&lt;p&gt;When we program in Clojure we never clone anything. Why is that? Well its because the day-to-day operations we perform on collections always automatically create what appear to be brand new, modified, copies. Part of the magic of Clojure is that this illusion is efficiently maintained. Hint: your structures aren’t really deep cloned every time you would otherwise mutate them. The &lt;a href=&quot;http://clojure.org/data_structures&quot;&gt;Clojure Data Structures page&lt;/a&gt; explains it well.&lt;/p&gt;

&lt;p&gt;Can we use the same idea to completely side-step this problem in Ruby? Well yes, we can! Some smart people already created a Clojure-like immutable collections library for Ruby. The &lt;a href=&quot;https://github.com/hamstergem/hamster&quot;&gt;Hamster Gem&lt;/a&gt; gives you a set of collection classes that mirror the familiar Ruby ones like Hash and Array. But the Hamster classes provide immutable operations (&lt;a href=&quot;http://www.rubydoc.info/github/hamstergem/hamster/master&quot;&gt;Hamster API documentation is here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Here’s the Hamster code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'hamster'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# convert to immutable containers&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;containers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'front'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'nginx:1.9'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_ruby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;containers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nginx:1.9&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;front&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my-python-web-app:latest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my-python-web-app&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We convert the response to immutable collections and then we use map to create a brand new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;container_definitions&lt;/code&gt; array (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vector&lt;/code&gt;). We examine each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt; in turn. If a hash has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:name&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'front'&lt;/code&gt; we apparently create a brand new hash. Hamster magic takes care of making that apparent duplication efficient. The new structure will share the unmodified parts of the original. Only the modified parts will require extra storage.&lt;/p&gt;

&lt;p&gt;This is fine if we only need to modify one collection. But what if we wish to retain the deep structure? The Hamster example just given isn’t actually doing everything our original Ruby example did. This first Hamster example is only creating a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;containers&lt;/code&gt; vector. What about the enclosing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task_definition&lt;/code&gt; hash?&lt;/p&gt;

&lt;p&gt;It is not necessarily obvious that immutable versions of Hash and Array will be sufficient for this task. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;response&lt;/code&gt; structure is a hash containing a hash containing an array of hashes. Will Hamster provide a way for us to modify these deep structures in nested containers and create new nested containers (i.e. create the illusion of creating new nested containers)?&lt;/p&gt;

&lt;p&gt;The answer is “yes!”. &lt;a href=&quot;https://github.com/hamstergem/hamster#transformations&quot;&gt;Hamster provides an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in()&lt;/code&gt; method&lt;/a&gt; that works just like &lt;a href=&quot;http://clojuredocs.org/clojure.core/update-in&quot;&gt;Clojure’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update-in()&lt;/code&gt; function&lt;/a&gt;. It’s accessed as a method on Hamster’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vector&lt;/code&gt; classes and it is generic enough to transform deep structures consisting of Hashes and Vectors.&lt;/p&gt;

&lt;p&gt;Hamster &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in()&lt;/code&gt; takes a path specification of “keys” (hash keys and array indices) into your deep (hash and array) structure and applies a block to the target value, deep within the structure. Applying that block modifies the target value, resulting (apparently) in a new collection object. As it unwinds the stack, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in()&lt;/code&gt; modifies enclosing collections (apparently) creating new ones until it reaches the top-most collection. Because it’s all built on Hamsters efficient collection primitives, the whole thing is efficient.&lt;/p&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in&lt;/code&gt; you could, for instance, update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:image&lt;/code&gt; on container 0 to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx:1.9&lt;/code&gt; like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;rv2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'nginx:1.9'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_ruby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rv2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition_arn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;some-arn-string&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;front&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nginx:1.9&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my-python-web-app&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my-python-web-app:latest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]}}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can see the Clojure philosophy at work here. An array or vector is very much like a hash in that an array maps keys to values. In the case of an array or vector the keys all happen to be natural numbers. Hamster has stacked the deck by providing a core set of methods on both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hamster::Vector&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hamster::Hash&lt;/code&gt;, that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in()&lt;/code&gt; can rely on, specifically &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch(key,default)&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;put(key,val)&lt;/code&gt;. We Rubyists call this duck typing. Hamster’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in&lt;/code&gt; is described in the &lt;a href=&quot;http://www.rubydoc.info/github/hamstergem/hamster/master#Transformations&quot;&gt;&lt;em&gt;Transformations&lt;/em&gt; section of the Hamster API doc&lt;/a&gt;. Hamster defines &lt;a href=&quot;http://www.rubydoc.info/github/hamstergem/hamster/master/Hamster/Associable&quot;&gt;a mix-in module called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Associable&lt;/code&gt;&lt;/a&gt; that implements &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in()&lt;/code&gt; for classes that meet the criteria.&lt;/p&gt;

&lt;h2 id=&quot;not-quite-therewe-need-something-more&quot;&gt;Not Quite There—We Need Something More&lt;/h2&gt;

&lt;p&gt;This would be great if we always knew the index of the Vector element that we wanted to update. But in general we do not. What we really want to do is update whatever Vector element is a Hash with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:name&lt;/code&gt; equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'front'&lt;/code&gt;. Instead of specifying Vector offset ‘0’ we’d like to specify the element whose &lt;em&gt;value&lt;/em&gt; meets our criterion.&lt;/p&gt;

&lt;p&gt;What if we had a function called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_having()&lt;/code&gt; that could take a different kind of path specification e.g.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;update_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;               &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;update_having&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'front'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’ve created &lt;a href=&quot;https://rubygems.org/gems/hamstar&quot;&gt;a little gem called Hamstar&lt;/a&gt; that does just that. Dig:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'hamstar'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rv3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamstar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_having&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'front'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'nginx:1.9'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_ruby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rv3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;same&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Oh and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hamstar.update_having()&lt;/code&gt; uses the case comparison operator &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;===&lt;/code&gt; on your match value so you can use regexps and ranges and other interesting objects besides strings there. So if you wanted a case-insensitive match on the name you could:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;rv4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamstar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_having&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/FRONT/i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'nginx:1.9'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_ruby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rv4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;same&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Rather than injecting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_having()&lt;/code&gt; into Hamster classes (as a method) I opted to implement it as a (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module_function&lt;/code&gt;) on the Hamstar module. This is less intrusive and might make it a little more apparent that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_having()&lt;/code&gt; operates on compound structures of arrays and vectors.&lt;/p&gt;

&lt;p&gt;The name “Hamstar” is a portmonteau of “Hamster” and “star”. I chose the name because of the other feature Hamstar adds, and that is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Kleene_star&quot;&gt;Kleene star&lt;/a&gt;. You can use the Kleene star to match all container elements.&lt;/p&gt;

&lt;p&gt;Say you wanted to capitalize the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:name&lt;/code&gt; value on every element of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:container_definitions&lt;/code&gt; array. Doing this with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in()&lt;/code&gt; would require one call for each element of the array. With Hamstar you can do it in a single call using the Kleen star &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'*'&lt;/code&gt;. Here we use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'*'&lt;/code&gt;at the top-level to select every association in the top-level hash, and another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'*'&lt;/code&gt; to select every element of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:container_definitions&lt;/code&gt; value:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;rv5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamstar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_having&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;capitalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_ruby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rv5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition_arn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;some-arn-string&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Front&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nginx:1.7&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My-python-web-app&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my-python-web-app:latest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]}}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The addition of the Kleene star was inspired by the &lt;a href=&quot;https://github.com/boxed/instar&quot;&gt;Instar Clojure library&lt;/a&gt;. That’s an interesting and powerful library. It doesn’t, however, provide the associative selection that &lt;a href=&quot;https://github.com/Bill/hamstar&quot;&gt;Hamstar&lt;/a&gt; offers.&lt;/p&gt;

&lt;p&gt;And finally, if none of those matchers work for you, you can specify your own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Proc&lt;/code&gt; as a matcher. Here we capitalize all names containing an ‘f’:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;rv6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamstar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_having&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/f/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;capitalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_ruby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rv6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:task_definition_arn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;some-arn-string&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;ss&quot;&gt;:container_definitions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Front&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nginx:1.7&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my-python-web-app&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my-python-web-app:latest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]}}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Thinking like a functional programmer is new territory for me. There is a menagerie of data structures, algorithms, and techniques to master. The rewards are considerable.&lt;/p&gt;

&lt;p&gt;It’s fun and even profitable to take some of these ideas back to our Ruby cave for experimentation. You’ve seen how the &lt;a href=&quot;https://github.com/hamstergem/hamster&quot;&gt;Hamster Gem&lt;/a&gt;’s immutable collections can be used to do an everyday job in a different way. My &lt;a href=&quot;https://rubygems.org/gems/hamstar&quot;&gt;Hamstar Gem&lt;/a&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_having()&lt;/code&gt; extended the functionality of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in()&lt;/code&gt;, with associative selection criteria and a Kleene star.&lt;/p&gt;

&lt;p&gt;You may look at the original (idomatic) Ruby and conclude that it is more readable than the more functional alternative. You may also encounter surprising results from your new “functional” code. For instance:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:'Pat'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Pat&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'sy'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Patsy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'sy'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Patsysy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;“The collection &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; is immutable—but it appears that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; was modified by the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_in()&lt;/code&gt;”, you say. What happened here is we used a mutating operation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&amp;lt;&lt;/code&gt; on a String stored in an immutable collection. The &lt;a href=&quot;https://github.com/hamstergem/hamster&quot;&gt;Hamster main page&lt;/a&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;While Hamster collections are immutable, you can still mutate objects stored in them. We recommend that you don’t do this, unless you are sure you know what you are doing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we had written it this way, we would have gotten the expected results:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:'Pat'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Pat&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'sy'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Patsy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'sy'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hamster&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Patsysy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Since the whole Ruby language, environment and eco-system formed around mutability, while functional programming in Ruby is possible, there are many pitfalls. There is a heavy intellectual burden, at least initially, when you attempt to go functional in Ruby.&lt;/p&gt;

&lt;p&gt;My experience experimenting with functional programming in Ruby mirrors what Mister Miyagi said about karate:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Miyagi: get squish just like grape. Here, karate, same thing. Either you karate do “yes” or karate do “no.” You karate do “guess so,”&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;from &lt;a href=&quot;http://www.imdb.com/title/tt0087538/quotes?item=qt0449931&quot;&gt;IMDB Karate Kid quotes&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Clojure, on the other hand, started from a more functional place. Immutability is the default there. While you can port much of Clojure to Ruby, you may find after you’re done, that you’ve created a somewhat confusing and hostile environment.&lt;/p&gt;
</description>
        <pubDate>Sun, 01 Nov 2015 05:44:41 +0000</pubDate>
        <link>http://memerocket.com/2015/11/01/hamstar-transforms-immutable-ruby-collections-better</link>
        <guid isPermaLink="true">http://memerocket.com/2015/11/01/hamstar-transforms-immutable-ruby-collections-better</guid>
        
        
        <category>Ruby</category>
        
        <category>Functional Programming</category>
        
        <category>AWS</category>
        
        <category>Clojure</category>
        
      </item>
    
      <item>
        <title>Let Who Die?</title>
        <description>&lt;p&gt;I watched &lt;a href=&quot;http://www.youtube.com/watch?v=PepQF7G-It0&quot;&gt;Ron Paul’s response to Wolf Blitzer’s medical insurance question&lt;/a&gt; and I do not hear anybody in the audience shouting “let him die”. I do hear strong applause in response to Paul’s comment “that’s what freedom is all about—taking your own risks”. And I do hear a couple audience member shouting “yeah!” to Blitzers question “are you saying that society should just let him die?” The audience reaction got a lot of attention this week. But it seems to me Blitzers line of questioning (and lack of follow-up) was the bigger story.&lt;/p&gt;

&lt;p&gt;The first thing is that Blitzers hypothetical “young man, makes a good living” is a bit of a straw man in this context. The point of the healthcare debate is not so much about the young man who makes a good living. It’s more about the young man or woman who does not make a “good living”. It’s about the baseline we are willing to accept as a society. How low are we willing to set the bar?&lt;/p&gt;

&lt;p&gt;Secondly, it seems to me that the obvious follow-up question Blitzer should have asked is:&lt;/p&gt;

&lt;blockquote&gt;Blitzer: OK Mr. Paul, well when that (uninsured) young man shows up in the emergency room after a car accident are the doctors going to treat him or not?&lt;/blockquote&gt;

&lt;p&gt;Now make that young man an old grandpa with Alzheimer’s disease. Or a baby with &lt;a href=&quot;http://en.wikipedia.org/wiki/Human_respiratory_syncytial_virus&quot;&gt;RSV&lt;/a&gt;. Yes I know we have Medicaid for the very poor and Medicare for the elderly. But lots of folks are falling through the cracks (about 1 in 6)!&lt;/p&gt;

&lt;p&gt;Then it might have been nice if Blitzer quizzed Paul on the economics so we could listen to Paul’s’ explanation of how if we just let the market do it’s job, see, and privatized everything, our healthcare costs would not be rising at double-digit annual rates.&lt;/p&gt;

&lt;p&gt;So fie on Blitzer, for the straw man of a scenario and the total lack of follow-up.&lt;/p&gt;
</description>
        <pubDate>Fri, 16 Sep 2011 18:22:35 +0000</pubDate>
        <link>http://memerocket.com/2011/09/16/let-who-die</link>
        <guid isPermaLink="true">http://memerocket.com/2011/09/16/let-who-die</guid>
        
        
        <category>healthcare</category>
        
        <category>libertarianism</category>
        
      </item>
    
      <item>
        <title>Finely Tuned</title>
        <description>&lt;p&gt;&lt;img src=&quot;/assets/2011-09-16-finely-tuned/tuning-fork.jpg&quot; alt=&quot;Tuning Fork&quot; /&gt;
“Shostakovich and Stalin by Mait Jüriado via Flickr”&lt;/p&gt;

&lt;p&gt;It’s hard to decide whether to loathe or applaud &lt;a href=&quot;http://biologos.org/&quot;&gt;The BioLogos Forum&lt;/a&gt;. The purpose of the project is to convince evangelical Christians that evolution is real. Nobody can argue with that right? The world (certainly the United States) would be better off if fewer people thought the planet was 6000 years old and &lt;a href=&quot;http://www.gallup.com/poll/114544/darwin-birthday-believe-evolution.aspx&quot;&gt;cave men rode dinosaurs&lt;/a&gt; right?&lt;/p&gt;

&lt;p&gt;The part that I often get hung up on though, is the inconsistency of the argument put forth on BioLogos. On the one hand, they make the case that we should all believe in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Evolution&quot;&gt;theory of evolution&lt;/a&gt; because of all the really great evidence for it. Evidence is important right? We are all interested in figuring out how things &lt;em&gt;really&lt;/em&gt; work right? Of course, especially when we are talking about something as important as life on this planet, where it came from, and where it’s headed.&lt;/p&gt;

&lt;p&gt;But then BioLogos takes a sharp left turn. Observation and evidence and logic are really important when studying biology, but when it comes to everything else, we should really not apply those criteria. It’s &lt;a href=&quot;http://en.wikipedia.org/wiki/Non-overlapping_magisteria&quot;&gt;NOMA&lt;/a&gt; you see. The crux of their position is that you don’t have to throw out your Christianity in order to believe in the theory of evolution.&lt;/p&gt;

&lt;p&gt;One thing that has always bugged me about that position is that it seems like such a small victory. The scientific method is so much more powerful than that. Why stop with the theory of evolution I say. Why not slay more sacred cows while you’re at it? Line ‘em up and knock ‘em down. You thought the earth was flat. Busted. You thought demons caused illness. Busted. You thought we all evolved from a single breeding pair (Adam+Eve). Busted. So far so good. Why not go on… You think there is a &lt;a href=&quot;http://www.apenotmonkey.com/2011/09/16/super-hero-god/&quot;&gt;magic bearded guy&lt;/a&gt; who intercedes on your behalf? Busted. You think there is a “spirit” that enters your body at conception and leaves it at death. Busted.&lt;/p&gt;

&lt;p&gt;I get enthused. And then I am reminded of my real world experience discussing and debating these very issues with friends and family. I’m reminded of how hard it is to change someone’s mind. And when I think of that, I become much more sympathetic to the BioLogos approach. Maybe the scientists have to excuse (temporary) hypocrisy in the interest of progress. Any progress. Small. Slow. Progress.&lt;/p&gt;

&lt;p&gt;One can view BioLogos cynically (and I often do). But one can also detect a sort of genius at work. A great example of this is the recent series of articles by &lt;a href=&quot;http://biologos.org/about/team/dennis-venema&quot;&gt;Dennis Venema&lt;/a&gt; about his journey from de facto Intelligent Design proponent to evolutionary theory advocate:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://biologos.org/blog/from-intelligent-design-to-biologos-part-1-early-years&quot;&gt;From Intelligent Design to BioLogos, Part 1: Early years
&lt;/a&gt;&lt;a href=&quot;http://biologos.org/blog/from-intelligent-design-to-biologos-part-2-embracing-intelligent-design&quot;&gt;From Intelligent Design to BioLogos, Part 2: Embracing Intelligent Design
&lt;/a&gt;&lt;a href=&quot;http://biologos.org/blog/from-intelligent-design-to-biologos-part-3-an-unexpected-opportunity&quot;&gt;From Intelligent Design to BioLogos, Part 3: An Unexpected Opportunity
&lt;/a&gt;&lt;a href=&quot;http://biologos.org/blog/from-intelligent-design-to-biologos-part-4-reading-behe&quot;&gt;From Intelligent Design to BioLogos, Part 4: Reading Behe
&lt;/a&gt;&lt;a href=&quot;http://biologos.org/blog/from-intelligent-design-to-biologos-part-5-epilogue&quot;&gt;From Intelligent Design to BioLogos, Part 5: Epilogue&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Venema is the perfect messenger: young, handsome, devoutly religious. His rhetoric is scientifically accurate (on the subject of evolutionary biology) and at the same time perfectly tuned to his audience. Nowhere is BioLogos’ perfect sense of their audience more evident than in the &lt;a href=&quot;http://biologos.org/blog/ask-an-evolutionary-creationist-a-qa-with-dennis-venema&quot;&gt;Ask an Evolutionary Creationist: A Q&amp;amp;A with Dennis Venema&lt;/a&gt;. Just look at how this question is posed:&lt;/p&gt;

&lt;blockquote&gt;7. From Jane (from her husband, an atheist): All of the questions posted so far approach the topic from the viewpoint of assuming belief in a god. As an atheist, I don’t share that assumption. (For those who might not appreciate it, evolution offers a mechanism for understanding the existence of living organisms that doesn’t require the existence of a god.) If you transitioned from an anti-evolutionary/pro-intelligent design view to an evolutionary creationist view a few years ago,” why didn’t you keep going and just embrace evolution and drop the theistic aspect?&lt;/blockquote&gt;

&lt;p&gt;For those who haven’t spent much time on BioLogos I must explain that there is almost no real debate on the site itself. Through their &lt;a href=&quot;http://biologos.org/blog/ground-rules-for-commenting&quot;&gt;ground rules for commenting&lt;/a&gt; and their diligent enforcement, the comment section is little more than an echo chamber. Question 7 (above) though is a masterwork of subtle self-inflicted echo chamber intrusion. We have Jane (not an atheist), interceding on behalf of her husband (an atheist) with a substantive question. And it’s the very same question that’s been on my mind all along! Venema’s response, while unsatisfying, represents a fair piece of rhetoric. I admire the way Venema turns &lt;a href=&quot;http://en.wikipedia.org/wiki/God_of_the_gaps&quot;&gt;God of the Gaps&lt;/a&gt; around on itself in his response:&lt;/p&gt;

&lt;blockquote&gt;This (Jane's husband's position) is a God-of-the-gaps approach, where God has less and less to do as we understand more and more how nature works (and a view I reject). Logically, if I held this view I would view science as an inherently evil activity, since any natural explanation diminishes the activity of God from this viewpoint.&lt;/blockquote&gt;

&lt;p&gt;Did you see what he did there? He responds to the atheist, but he’s playing to the gallery. It is brilliant. The side effect is that he may just be able to convince his co-religionists that he’s not such a bad guy after all. He’s not an uppity scientist. He’s a true believer. Maybe there really is something to this evolution stuff.&lt;/p&gt;
</description>
        <pubDate>Fri, 16 Sep 2011 00:41:11 +0000</pubDate>
        <link>http://memerocket.com/2011/09/16/finely-tuned</link>
        <guid isPermaLink="true">http://memerocket.com/2011/09/16/finely-tuned</guid>
        
        
        <category>evolution</category>
        
        <category>religion</category>
        
      </item>
    
      <item>
        <title>Google Sites Adds Keyboard Shortcuts</title>
        <description>&lt;p&gt;&lt;img src=&quot;/assets/2010-12-21-google-sites-adds-keyboard-shortcuts/screen-shot-2010-12-21-at-3-32-00-pm.png&quot; alt=&quot;screen shot&quot; /&gt;
I love Google Sites (wiki). I just noticed a whole bunch of keyboard shortcuts on the “More actions” menu. More to love!&lt;/p&gt;
</description>
        <pubDate>Tue, 21 Dec 2010 23:38:41 +0000</pubDate>
        <link>http://memerocket.com/2010/12/21/google-sites-adds-keyboard-shortcuts</link>
        <guid isPermaLink="true">http://memerocket.com/2010/12/21/google-sites-adds-keyboard-shortcuts</guid>
        
        
        <category>Google Apps</category>
        
      </item>
    
      <item>
        <title>Of Workmen, Tools and Logical Argument</title>
        <description>&lt;p&gt;I’ve often heard the saying “It’s a poor workman who blames his tools”.  Remember in 2009: &lt;a href=&quot;http://unlimitednovelty.com/2009/04/twitter-blaming-ruby-for-their-mistakes.html&quot;&gt;Twitter: blaming Ruby for their mistakes&lt;/a&gt;. While I agree with the substance of that post (that Twitter could’ve picked different tools or made Ruby suffice), seeing that saying again kind of set me off. Hence the present missive…&lt;/p&gt;

&lt;p&gt;Whenever I hear (It’s a poor workman who blames his tools) used as a blanket statement it bugs me. You know, some tools really are better than others. And you know, sometimes a (workman) chooses or must make do with poor ones. Again, I’m not talking about Ruby here—I’m talking about that saying.&lt;/p&gt;

&lt;p&gt;A &lt;a href=&quot;http://www.google.com/search?hl=en&amp;amp;q=workman+blames+tools+origin&quot;&gt;quick search&lt;/a&gt; yielded &lt;a href=&quot;http://www.phrases.org.uk/bulletin_board/18/messages/587.html&quot;&gt;some fascinating history&lt;/a&gt; on the origins of that saying. It looks like the saying started off rather differently:&lt;/p&gt;

&lt;blockquote&gt;Mauves ovriers ne trovera ja bon hostill. [A bad workman will never find a good tool.] (French proverb, late 13th C. )&lt;/blockquote&gt;

&lt;p&gt;And that usage prevailed for about six centuries or so until this:&lt;/p&gt;

&lt;blockquote&gt;Good workmen never quarrel with their tools. (Byron, _Don Juan_, 1818)&lt;/blockquote&gt;

&lt;p&gt;which is pretty close to the prevalent version I hear all the time in the software community.&lt;/p&gt;

&lt;p&gt;The earliest version says (a poor workman can’t do good work, no matter how good the tools are). Now I can get behind that one. No controversy there.&lt;/p&gt;

&lt;p&gt;The latest version says a good workman can do good work no matter how poor the tools are. That presumes that the workman cannot choose his tools. For if he could choose his tools then he would be evaluated on his ability to choose them, and choosing bad ones would reflect poorly on his ability. Or perhaps the workman wouldn’t even bother choosing tools at all since all tools are equally usable (to the good workman.) And that just seems absurd on its face.&lt;/p&gt;

&lt;p&gt;Tools do matter, and the ability to pick good ones often sets the very best workmen apart from their peers.&lt;/p&gt;
</description>
        <pubDate>Sun, 05 Dec 2010 23:04:37 +0000</pubDate>
        <link>http://memerocket.com/2010/12/05/of-workmen-tools-and-logical-argument</link>
        <guid isPermaLink="true">http://memerocket.com/2010/12/05/of-workmen-tools-and-logical-argument</guid>
        
        
        <category>tool</category>
        
      </item>
    
      <item>
        <title>Github Implements Agency-Aware Identity</title>
        <description>&lt;p&gt;[caption id=”attachment_304” align=”alignleft” width=”277” caption=”Github lets you specify your agency context”]&lt;a href=&quot;/assets/2010-07-07-github-implements-agency-aware-identity/screen-shot-2010-07-06-at-6-01-20-pm.png&quot;&gt;&lt;img src=&quot;/assets/2010-07-07-github-implements-agency-aware-identity/screen-shot-2010-07-06-at-6-01-20-pm.png&quot; alt=&quot;screenshot of Github's new context selector for organizations&quot; /&gt;&lt;/a&gt;[/caption]&lt;/p&gt;

&lt;p&gt;Github gave me a whole new reason to love them last week when they introduced &lt;a href=&quot;http://lesscode.org/2006/04/15/many-lives-just-one-you/&quot;&gt;agency-aware identity&lt;/a&gt; in their new &lt;a href=&quot;http://github.com/blog/674-introducing-organizations&quot;&gt;organizations&lt;/a&gt; offering. Crazy cool. Now each of my clients can have their own Github organization and I can participate in each! Same goes for each of my Open Source projects. And I can use it for a day job if I had such a thing. And all with one identity—one set of credentials. Brilliant Github!&lt;/p&gt;
</description>
        <pubDate>Wed, 07 Jul 2010 01:10:25 +0000</pubDate>
        <link>http://memerocket.com/2010/07/07/github-implements-agency-aware-identity</link>
        <guid isPermaLink="true">http://memerocket.com/2010/07/07/github-implements-agency-aware-identity</guid>
        
        
        <category>identity</category>
        
        <category>usability</category>
        
        <category>Web as Platform</category>
        
      </item>
    
      <item>
        <title>Watch a Video While You Work</title>
        <description>&lt;p&gt;I like to have a TED or SALT talk playing while I work on something mindless. The problem is that on my single 15” display, there isn’t really enough room to keep my work and the video (window) side-by-side. I’d like to designate the video window as the top window so that it never gets buried.&lt;/p&gt;

&lt;p&gt;[caption id=”attachment_300” align=”alignleft” width=”171” caption=”Unsanity WindowShade X Icon”]&lt;a href=&quot;/assets/2010-06-17-watch-a-video-while-you-work/screen-shot-2010-06-17-at-2-31-19-pm.png&quot;&gt;&lt;img src=&quot;/assets/2010-06-17-watch-a-video-while-you-work/screen-shot-2010-06-17-at-2-31-19-pm.png&quot; alt=&quot;image of window bar w/ WindowShade X icon&quot; /&gt;&lt;/a&gt;[/caption]&lt;/p&gt;

&lt;p&gt;I found two OS X solutions, each of which appear to be OS X window manager hacks to let you force a window to float atop all the others: &lt;a href=&quot;http://infinite-labs.net/afloat/&quot;&gt;∞labs Afloat&lt;/a&gt; and &lt;a href=&quot;http://unsanity.com/haxies/wsx&quot;&gt;Unsanity WindowShade X&lt;/a&gt;. I installed the latter and can attest that (after a reboot) it will indeed keep a browser window afloat. Just select the window of interest and hit the command key twice (⌘-⌘). The keystroke is configurable.&lt;/p&gt;

&lt;p&gt;WindowShade X relies on &lt;a href=&quot;http://unsanity.com/haxies/ape&quot;&gt;Unsanity’s Application Enhancer&lt;/a&gt;. I was concerned about security vulnerabilities introduced by that thing but since my Google searching didn’t turn up any obvious warnings I went ahead with it.&lt;/p&gt;
</description>
        <pubDate>Thu, 17 Jun 2010 21:25:27 +0000</pubDate>
        <link>http://memerocket.com/2010/06/17/watch-a-video-while-you-work</link>
        <guid isPermaLink="true">http://memerocket.com/2010/06/17/watch-a-video-while-you-work</guid>
        
        
        <category>Apple</category>
        
        <category>usability</category>
        
      </item>
    
      <item>
        <title>Run Google Chrome on Your Mac Now (with Extensions)</title>
        <description>&lt;p&gt;Google Chrome runs on your Mac now. Google Chrome supports Extensions now. Unfortunately, Google Chrome on your Mac doesn’t support extensions now.&lt;/p&gt;

&lt;p&gt;Well that’s not exactly true. It’s hard to find, but you can get the developer build of Chrome for the Mac. It’s prebuilt on the &lt;a href=&quot;http://build.chromium.org/buildbot/snapshots/chromium-rel-mac/&quot;&gt;Chromium Buildbot Snapshots for Mac Page&lt;/a&gt;. Scroll to the bottom and download the latest Zip archive. It contains the app (Chromium) which you just drag to your Applications folder.&lt;a href=&quot;/assets/2009-12-17-run-google-chrome-on-your-mac-now-with-extensions/screen-shot-2009-12-17-at-7-47-36-am1.png&quot;&gt;&lt;img src=&quot;/assets/2009-12-17-run-google-chrome-on-your-mac-now-with-extensions/screen-shot-2009-12-17-at-7-47-36-am1.png?w=300&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After it’s in place, use it to browse to the &lt;a href=&quot;https://chrome.google.com/extensions/&quot;&gt;Official Google Chrome Extensions&lt;/a&gt; site. Then check out the &lt;a href=&quot;https://chrome.google.com/extensions/detail/okanipcmceoeemlbjnmnbdibhgpbllgc&quot;&gt;Google Quick Scroll Extension&lt;/a&gt;, which continues your Google search beyond the results page, right on the third-party pages you jump to.&lt;/p&gt;
</description>
        <pubDate>Thu, 17 Dec 2009 16:06:03 +0000</pubDate>
        <link>http://memerocket.com/2009/12/17/run-google-chrome-on-your-mac-now-with-extensions</link>
        <guid isPermaLink="true">http://memerocket.com/2009/12/17/run-google-chrome-on-your-mac-now-with-extensions</guid>
        
        
        <category>OS X</category>
        
        <category>tool</category>
        
      </item>
    
  </channel>
</rss>
