Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to make Ruby var= return value assigned, not value passed in?
    primarykey
    data
    text
    <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>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload