Sorry, somehow I seem to have forgotten to send this earlier.
>> Hi,
>> I just had a use case where I wanted to have several counters and not
>> store them in a Hash because of the nicer syntax of OpenStruct.
>> Currently, the code has to do
>> counters = OpenStruct.new
>> ...
>> counters.foo ||= 0
>> counters.foo += 1
>> For obvious reasons I'd like to get rid of the initialization.
>> The suggestion would be to do this: if the argument to
>> OpenStruct#initialize is not a Hash use it as default value which is
>> returned for undefined properties. As far as I can see this won't
>> break existing code since the default is nil. With the change one
>> could do
>> counters = OpenStruct.new 0
>> ...
>> counters.foo += 1
>> We could go even further and copy the Hash approach by also allowing a
>> block which is invoked when a property is accessed for the first time.
>> Block argument would be the symbol of the property and the return
>> value would be used to initialize the property. Then you could do
>> data = OpenStruct.new {}
>> ...
>> data.animals << "cat" << "dog"
>> or even
>> data = OpenStruct.new do |sym|
>> case sym
>> when :animals :
>> when :dictionary : {}
>> end
>> end
>> In other words: declarative lazy initialization.
>> Again, existing code would not be affected.
>> What do others think?
> I recently submitted a patch that allowed OpenStruct to take a self
> yielding block, e.g you could do:
> data = OpenStruct.new do |o|
> o.animals =
> o.dictionary = {}
> end
> I don't really see that much use for complex lazy initialization as
> you suggest.
I don't view it so much as complex initialization but rather
declarative lazy initialization because it saves you the effort of
writing all those getter methods.
> Though, I can see the Hash block form being useful. Maybe
> that would be a better use of the block. Actually, both could be
> supported if we differentiate on the arity of the block. With two
> args:
> OpenStruct.new{ |o, k| o[k] = }
> Note, my patch also add # and #=, which are more important
> changes.
Yes, that's a good idea!
Glad you agree. Hell of a lot faster then send(key) and
send("#{key}=", val).
Mention it on ruby-core!
> Robert would you like to update my patch to support the Hash block
> notation and resubmit it?
I would rather not want to have two interpretations for the block
because this can easily lead to confusion and subtle bugs can creep in
when accidentally having the wrong arity.
That was my first though too, but then I considered it a bit more and
think it makes enough sense. If we are asking for just the OpenStruct
object, ie. OpenStruct.new{ |o| ... } then clearly we are interested
in working with the object. If we ask for the key as well, ie.
OpenStruct.new{ |o, k| ... } then it is also clear we are instead
interested in doing something with a key. It's really not any
different in principle from other method interfaces, like using one or
two arguments with #slice.
T.
···
On Sep 6, 1:27 pm, "Robert Klemme" <shortcut...@googlemail.com> wrote:
2008/9/5 Trans <transf...@gmail.com>:
> On Sep 5, 7:54 am, "Robert Klemme" <shortcut...@googlemail.com> wrote: