On Tue, Sep 25, 2012 at 8:13 PM, Gary Weaver <[email protected]> wrote:
> Is it possible for initialize to return an existing object instead of a
> new instance?
First of all, it's totally meaningless what #initialize returns.
Object creation is done inside the class's method #new. #initialize
is just an instance method which happens to be invoked on a newly
allocated object (that method exists as well). So basically you can
imagine it to work like this
class Class
def new(*a, &b)
x = allocate
x.send(:initialize, *a, &b)
x
end
end
So, yes, you can modify a class's method #new to return anything you like.
Side note, if you implement that method on your own I find this a tad
more elegant:
class Class
def new(*a, &b)
allocate.tap {|x| x.send(:initialize, *a, &b)}
end
end
> Specifically curious about whether it would be possible to implement a
> StringPool in Ruby such that the same object with same object_id would
> be returned if you tried to construct with the same value,
Easy:
string_pool = Hash.new {|h,s| h[s.freeze] = s}
irb(main):002:0> 5.times { puts string_pool["foo"].object_id}
-1072382248
-1072382248
-1072382248
-1072382248
-1072382248
=> 5
irb(main):003:0> 5.times.map { string_pool["foo"].object_id }.uniq
=> [-1072382248]
Note: the call of #freeze is necessary since a Hash will dup a mutable
String key to avoid aliasing effects. That's a feature of Hash.
> unless a bang
> method (like chomp!) were called on the object in which case instead of
> returning the same object instance from the bang method, it would return
> a different object instance. I told someone that this would be a massive
> change since it would break these two assumptions:
Right. That'll be difficult since behavior of String instances would
need to be changed if they are in the pool. Hard to do and probably
not efficient.
> s = "Hello"
> s2 = "Hello"
> # s.object_id != s2.object_id
>
> s = "Hello"
> original_object_id = s.object_id
> s.chomp!('o')
> # original_object_id == s.object_id
>
> But, maybe if it were possible to develop this as a gem, people could
> use at their own risk.
>
> Also, it just seemed like a neat idea (not that it would work in the
> String case?) if you could do something in the initializer to abandon
> the instance that was being created and instead return a different
> object from the initializer, like one that already exists. Even if this
> isn't possible currently, what issues would one run into trying to
> implement support for this? Thanks!
See above, you need to modify your class's #new method. Silly example:
irb(main):006:0> class George
irb(main):007:1> attr_reader :num
irb(main):008:1> def initialize(x) @num = x.to_int end
irb(main):009:1> end
=> nil
irb(main):010:0> 3.times.map { George.new(1).object_id }
=> [-1072296698, -1072296708, -1072296718]
irb(main):011:0> 3.times.map { George.new(1).object_id }.uniq
=> [-1072308808, -1072308818, -1072308828]
OK, regular case: we get a new George for every int. Now we create the pool:
irb(main):013:0> class <<George
irb(main):014:1> alias _new new
irb(main):015:1> def new(x)
irb(main):016:2> @objects[x.to_int] ||= _new(x)
irb(main):017:2> end
irb(main):018:1> end
=> nil
Create the Array which is the pool:
irb(main):019:0> class George
irb(main):020:1> @objects=[]
irb(main):021:1> end
=> []
Now let's see:
irb(main):022:0> 3.times.map { George.new(1).object_id }
=> [-1072359978, -1072359978, -1072359978]
irb(main):023:0> 3.times.map { George.new(1).object_id }.uniq
=> [-1072359978]
Ah!
Note: all sorts of issues have to be considered which might be
introduced by this, i.e. memory leaks, concurrency issues etc. This
approach works best for immutable objects of course. Even then the
pool needs to be properly synchronized.
Kind regards
robert
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
-- You received this message because you are subscribed to the Google Groups
ruby-talk-google group. To post to this group, send email to
[email protected]. To unsubscribe from this group, send email
to [email protected]. For more options, visit this
group at https://groups.google.com/d/forum/ruby-talk-google?hl=en