On 23.11.2006 02:36, Victor "Zverok" Shepelev wrote:
> From: dblack / rubypal.com [mailto:dblack / rubypal.com] On Behalf Of
> dblack / wobblini.net
> Sent: Thursday, November 23, 2006 3:31 AM
>> On Thu, 23 Nov 2006, Victor "Zverok" Shepelev wrote:
>>
>>> Hi all.
>>>
>>> I have some huge class with aspects of functionality spreaded in several
>>> source files.
>>>
>>> And in some of those aspects there is the same picture:
>>> ---
>>> class MyClass
>>>  def push_something(obj)
>>>    @something_list ||= []
>>>    @something_list << obj
>>>  end
>>>
>>>  def use_something(i)
>>>    (@something_list ||= [])[i]
>>>  end
>>> end
>>> ---
>>>
>>> Then I note (through profiler) various push_XXX spend too much time in
>>> checking is @XXX_list initialized. Then I change it:
>>>
>>> ---
>>> class MyClass
>>>  alias :initialize_without_something :initialize
>>>
>>>  def initialize(*arg)
>>>    initialize_without_something(*arg)
>>>    @something_list = []
>>>  end
>>>
>>>  def push_something(obj)
>>>    @something_list << obj
>>>  end
>>>
>>>  def use_something(i)
>>>    @something_list[i]
>>>  end
>>> end
>>> ---
>>>
>>> Now push_XXX and use_XXX work cleaner and faster, but all those
>> initialize
>>> aliases (now I have 5 or 6) don't seem to be very elegant.
>>>
>>> Is there better solution?
>>>
>>> (to be clear, all those push_XXX are NOT similar - some of them push
>> object
>>> to hashes, others to arrays, params count differ and so on - so, they
>> can't
>>> be generated at once through metaprogramming)
>> In your second example, what purpose does initialize_without_something
>> serve?  I'm wondering why you don't just do:
>>
>>   def initialize
>>     @something_list = []
>>   end
>>
>> and then the other methods.
> 
> Because it would hide initialization code defined in other files for the
> same class.
> 
> class A
>  def initialize; p 1 end
> end
> 
> class A
>  def initialize; p 2 end
> end
> 
> class A
>  def initialize; p 3 end
> end
> 
> A.new # => 3

Frankly, I believe this is not a too good idea.  There should be one 
main place (i.e. file) responsible for this class's definition and all 
other places should only add to that class.  Changing initialize's 
signature would certainly be not a good idea either.

If you feel, you have to initialize additional fields, then this is a 
cleaner solution - and also more modular:

class Foo
   def initialize(a,b,c)
     super
     @a=a
     @b=b
   end
end

module Mixin
   def initialize(*a,&b)
     super
     @foo = []
   end
end

Then you can safely do in another place:

class Foo
   include Mixin
end

and construction will still work ok plus you can use that module in 
several places.

Another clean solution:

class Foo
   def use_sth() @something ||= [] end
   def push_sth(x) something << x end
end

Btw, you can make your push_something more efficient by using a single 
statement:

def push_sth(x)
   (@sth ||= []) << x
end

Kind regards

	robert