# Copy-on-write in Ruby

I need to return private collection and

1. avoid calling code modifying them
2. avoiding copying overhead if possible

So I thought of returning copy-on-write arrays, hashes, and sets.

I couldn't find any implementations of these, so I tried my own.

require 'delegate'
require 'set'

module Cow end

class Cow::Base < SimpleDelegator
def initialize(obj)
super
obj.freeze
@copied = false
end

def method_missing(*args, &block)
if @copied
super
else
begin
super
rescue RuntimeError => e
if e.to_s.include? 'can\'t modify frozen'
__setobj__ __getobj__.dup
@copied = true
super
else
raise
end
end
end
end
end

module CowClass
def cow
Cow::Base.new self
end
end

class Array
include CowClass
end

class Hash
include CowClass
end

class Set
include CowClass
end


And then used like

a = [1, 2, 3]
b = a.cow
b << 4
puts a.join ' ' # 1 2 3
puts b.join ' ' # 1 2 3 4


Suggestions? Applause? Boos?

• When I run your code, I get a and b are both [1, 2, 3, 4] – Zack Oct 11 '16 at 14:48
• @Zack, I forgot the freeze. FIxed. – Paul Draper Oct 11 '16 at 19:07
• This strategy seems likely to cause confusion, as you're changing the semantics of operators like <<. I think it would be simpler and better to use immutable objects, and force your clients to use non-mutating methods like concat when they want to "write". That's just better ruby practice anyway. And you can avoid the whole issue.... – Jonah Oct 15 '16 at 21:34