title: How to make Ruby var= return value assigned, not value passed in?
body: <p>There's a nice idiom for adding to lists stored in a hash table:</p>
  
  <pre><code>(hash[key] ||= []) &lt;&lt; new_value
  </code></pre>
  
  <p>Now, suppose I write a derivative hash class, like the ones found in Hashie, which does a deep-convert of any hash I store in it. Then what I store will not be the same object I passed to the = operator; Hash may be converted to Mash or Clash, and arrays may be copied.</p>
  
  <p>Here's the problem. Ruby apparently returns, from the var= method, the value passed in, not the value that's stored. It doesn't matter what the var= method returns. The code below demonstrates this:</p>
  
  <pre><code>class C
    attr_reader :foo
    def foo=(value)
      @foo = (value.is_a? Array) ? (value.clone) : value
    end
  end
  
  c=C.new
  puts "assignment: #{(c.foo ||= []) &lt;&lt; 5}"
  puts "c.foo is #{c.foo}"
  puts "assignment: #{(c.foo ||= []) &lt;&lt; 6}"
  puts "c.foo is #{c.foo}"
  </code></pre>
  
  <p>output is</p>
  
  <pre><code>assignment: [5]
  c.foo is []
  assignment: [6]
  c.foo is [6]
  </code></pre>
  
  <p>When I posted this as a bug to Hashie, Danielle Sucher explained what was happening and pointed out that "foo.send :bar=, 1" returns the value returned by the bar= method. (Hat tip for the research!) So I guess I could do:</p>
  
  <pre><code>c=C.new
  puts "clunky assignment: #{(c.foo || c.send(:foo=, [])) &lt;&lt; 5}"
  puts "c.foo is #{c.foo}"
  puts "assignment: #{(c.foo || c.send(:foo=, [])) &lt;&lt; 6}"
  puts "c.foo is #{c.foo}"
  </code></pre>
  
  <p>which prints</p>
  
  <pre><code>clunky assignment: [5]
  c.foo is [5]
  assignment: [5, 6]
  c.foo is [5, 6]
  </code></pre>
  
  <p>Is there any more elegant way to do this?</p>