Skip to content

Instantly share code, notes, and snippets.

@ootoovak
Last active December 18, 2015 16:29
Show Gist options
  • Save ootoovak/5811499 to your computer and use it in GitHub Desktop.
Save ootoovak/5811499 to your computer and use it in GitHub Desktop.
Don't recreate another object if you don't need to.
# Want to pass in a hash or instance of object. Was hoping to avoid is_a? or creating a new object but
# think that can only be done with is_a? or overriding new. Also, I might be missing the point as
# avoiding is_a? should mean I am using Duck Typing but if I'm using Duck Typing then I shouldn't be
# checking object equality anyway. See RSpec test for details.
describe MyClass do
let(:hash) { { name: 'Duck Type', description: 'Quacks like a duck?' } }
before do
@my_instance_1 = MyClass.new(hash)
@my_instance_2 = MyClass.new(@my_instance_1)
end
it 'this is preferable' do
@my_instance_1.should equal(@my_instance_2)
end
it 'this is ok' do
@my_instance_1.should eq(@my_instance_2)
end
end
# Possilbe solutions involve overriding MyClass.new or buidling a constructor
# http://stackoverflow.com/questions/4888786/how-can-i-change-the-return-value-of-a-class-constructor-in-ruby
# Good old Rubber Duck Debugging
# Will only pass 1 of 2 tests
class MyClass
attr_accessor :name
attr_accessor :description
def initialize(args = {})
@name = args.fetch(:name, '')
@description = args.fetch(:description, '')
end
def fetch(key, default_value)
send(key) || default_value
end
end
# This one works as I originally wanted but requires a Class check and modifying new with I'm
# pretty sure can lead to bad things given how Ruby handles new and initialize.
class MyClass
attr_accessor :name
attr_accessor :description
def self.new(args = {})
args.is_a?(MyClass) ? args : super(args)
end
def initialize(args = {})
@name = args.fetch(:name, '')
@description = args.fetch(:description, '')
end
def fetch(key, default_value)
send(key) || default_value
end
end
@ootoovak
Copy link
Author

@eoinkelly yeah that is what I was going for at first. I wanted to just send back a pointer to that object if that object was already an instance of that class. Thinking it would save CPU and Mem by not copying the values over from one instance to another. Not that it is a huge deal (CPU/Mem) in my case but was more wondering if it could be done.

@eoinkelly
Copy link

Ah ok. In order to memoize the return value, you will need to keep track of all instances of that class that have been created in the system (so you can return an existing one if it matches the parameters). You could probably make MyClass store a reference to every instance it creates and then return one of them from initialize. That said, I think having a separate MyClassFactory that does this magic would be cleaner.

BTW your example makes name and description mutable. This is probably a bad idea as you will couple every user of one of these objects together in a potentially hilarious way.

Thanks for the chewy problem ;-)
HTH
/Eoin/

@ootoovak
Copy link
Author

@eoinkelly good catch. I'll look into that potential coupling. Guess I clone values to be save?

Also, would be keen on seeing how you would write your solution if you had a chance to fork this Gist sometime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment