barsoom / attr_extras

Takes some boilerplate out of Ruby with methods like attr_initialize.
MIT License
560 stars 31 forks source link

Issue 45 default values shared #46

Closed sammo1235 closed 1 year ago

sammo1235 commented 1 year ago

Using @frank-west-iii 's first code example, slightly modified, we can see that the default array value being passed is ultimately the same object used in all instances of the class:

class Foo
  arr = []
  puts arr.object_id
  aattr_initialize [:name, items: arr]
end

data = [
  { name: "One", items: [1, 2, 3] },
  { name: "Two", items: [4, 5, 6] },
]

results = data.each_with_object([]) do |datum, results|
  name, items = datum.values_at(:name, :items)
  foo = Foo.new(name: name)

  items.each do |n|
    foo.items << n
  end

  results << foo
end

results.each do |res|
  puts res.items.object_id
end

# => 860
# => 860
# => 860

To solve this I simply dupe the value on initialization so each instance gets its own unique object.

henrik commented 1 year ago

Good catch fix; thank you! ❤️

This will still share references with nested values like [[1,2,3]] – perhaps we want to do a deep dup. I'll have a think during our next cooldown in about 4 weeks.

henrik commented 1 year ago

Merged and released. Thanks so much for your contribution and your patience, @sammo1235 :)

I decided that a shallow dup is enough for now – if anyone wants to PR a deep dup, go for it!