From: RichardOnRails Date: 2011-01-24T03:10:34+09:00 Subject: Re: Easiest way in Ruby to express "given this, set target to this if nil or undefined, else increment by this" On Jan 23, 12:26 am, Jeremy Bopp wrote: > On 01/22/2011 10:50 PM, RichardOnRails wrote: > > > The following works,  but I'd prefer not to have to class values: > > > class Z > >     def self.show_z > >    @@zz ||= 0; @@zz += 1 > >    puts @@zz > >     end > > end > > Z.show_z   # => 1 > > Z.show_z   # => 2 > > Replace the @@'s with @'a so that you use a class instance variable > instead.  In this case it works effectively the same while avoiding the > nasty class variables. > > > > > I tried this: > > > $h = Hash.new(:y) > > def show_y > >     $h[:y] ||= 0; $h[:y] += 1 # => Error msg # Line 18 > >     puts $h[:y] > > end > > show_y > > show_y > > > but it doesn't pass muster with Ruby 1.8.6.  I get a complaint about > > the first line in show_y, which makes no sense IMHO: > > > TestOrEqual_operator.rb:18:in `show_y': undefined method `+' > > for :y:Symbol (NoMethodError) > >    from TestOrEqual_operator.rb:21 > > The error is ultimately the result of the way you initialized your Hash > instance.  By passing :y to the new method, you arranged for any > uninitialized key referenced within the hash to have the symbol :y as a > value.  Therefore, > > $h[:y] ||= 0 > > doesn't do anything because $h[:y] has a value of :y by default.  The > next statement then attempts to increment the value of $h[:y] by 1 and > fails because that value is :y and the + method is not defined for > Symbols.  If what I'm saying isn't exactly clear, try this: > > h = Hash.new(:howdy) > puts h['Say hello like a Texan!'] > puts h['Now say hello like a John Wayne!'] > > You could avoid this particular problem by simply setting $h to {} > rather than calling Hash.new(:y).  But why is a hash necessary for this > at all???  You could just as easily do this: > > def show_y >   $y ||= 0 >   $y += 1 >   puts $y > end > > This still leaves you using a global, but it's much simpler.  More > importantly, it works. ;-) > > > Also, I'd be able to use a succinct version of this without resorting > > to globals. > > Without knowing more about the problem you're trying to solve, it's hard > to provide a better response.  Apparently, you want to call a method > that automatically initializes some state when needed and then modify > and preserve that state between subsequent calls to that method.  That > state, be it a number as in your examples here or something else, has to > be stored somewhere. > > I'm not a fan of globals in general, so I would choose to keep the state > in a class as you did in your first example. > > -Jeremy Hi Jeremy, Thanks for that lucid explanation of where my error lay which in turn made the + method inappropriate. The app I'm working do have class and relevant methods defined, so using the scheme I playing with is fine in a class context. Again, thanks, Richard