On Sep 6, 1:27 ¨Âí¬ ¢ÒïâåòËìåííå¼óèïòôãõô®®®Àçïïçìåíáéì®ãïí¾ ÷òïôåº > Sorry, somehow I seem to have forgotten to send this earlier. > > 2008/9/5 Trans <transf... / gmail.com>: > > > > > > > On Sep 5, 7:54 am, "Robert Klemme" <shortcut... / googlemail.com> wrote: > >> 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. ¨Âéôôèãèáîçå ïî> >> 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. > >> ¨Âìïãë áòçõíåîô ÷ïõìâå ôèóùíâïì ïæ ôèðòïðåòôù áîôèòåôõòî > >> value would be used to initialize the property. ¨Âèåùïãïõìäï > > >> 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: > > > ¨ÂáôÏðåîÓôòõãô®îå÷ äï üï> > o.animals = [] > > o.dictionary = {} > > ¨Âîä > > > 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: > > > ¨ÂðåîÓôòõãô®îå÷û üïëü ïÛëÝ ÛÝ > > > 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.