Class variables in Ruby

Hello all,

I am trying to cache lookup table values from a database table into a
hash that is stored in a class variable. This will allow me to read and
store the id/descr value pairs from the database one time only after
which I store them in the hash and retrieve them from there.

The problem is the class variable appears to be cleared out each time a
new request comes in to my controller. I am using rails in the
development enrionment but I am hoping this is a Ruby issue. I thought
maybe rails was reloading the class each time a request comes in
because I read this is standard behavior in the development
environment. However, I believe the reloadable? method is supposed to
care of that?

Here is the code from my model class. The code is alwasy going to super
to read from the database. If anyone can steer me straight on this I
would appreciate it!

Thanks in advance.
Paul

class GrammarTenseCode < ActiveRecord::Base
    has_many :words
    @@cachedDescr = {}

    def self.reloadable?
       false
    end

    def descr
      if @@cachedDescr[id.to_s] == nil
          @@cachedDescr[id.to_s] = super
      else
          @@cachedDescr[id.to_s]
      end
    end
end

If you think reloading is happening, try:

@@cacheDescr = {} unless @@cacheDescr

Kirk Haines

···

On Sat, 19 Aug 2006, Paul wrote:

   @@cachedDescr = {}

@@cacheDescr = {} unless @@cacheDescr

Or, to be more idiomatic:

@@cache_descr ||= {}

···

--
Posted via http://www.ruby-forum.com/.

khaines@enigo.com wrote:

> @@cachedDescr = {}

If you think reloading is happening, try:

@@cacheDescr = {} unless @@cacheDescr

Kirk Haines

Hi Kirk,

I tried @@cacheDescr = {} unless @@cacheDescr but I get the same
results. I would expect the initialization of @@cacheDescr to take
place when the .rb package is loaded. I will keep playing with it and
post a solution when I figure it out.

Thanks,
Paul

···

On Sat, 19 Aug 2006, Paul wrote:

SOLUTION: Rails, in the development environment, was reloading the
class for every request coming into the application and therefore
causing the Class variable to be reset. Something I read led me to
believe I could add the following method to my class to cause it not to
be reloaded

    def self.reloadable?
        false
    end

That was false. To keep rails from reloading the class every time you
can change the ..\config\environments\development.rd file. It has a
"config.cache_classes = false" line that you can change to <true>
which will prevent the classes from being reloaded. You are REQUIRED to
stop the WEBrick server though to pick up this change as well as
whenever to want to pick up any recent coding changes. BUT, you can
change this parameter temporarily to test out Class variables that are
expected to store data throughout your session. Don't forget to change
it back to <false> to be back in the default mode which is the
desirable mode for development.

Which I usually prefer, but the variant that uses unless reads more like a sentence if a person isn't sure what's happening there.

I wish I could use a simple structure like that for constants.

Foo = 7 unless const_defined? :Foo

is wordier than I like.

Kirk Haines

···

On Sat, 19 Aug 2006, Daniel Waite wrote:

@@cacheDescr = {} unless @@cacheDescr

Or, to be more idiomatic:

@@cache_descr ||= {}

but the file may be getting loaded each time... depending on mode. fyi.

-a

···

On Sat, 19 Aug 2006, Paul wrote:

khaines@enigo.com wrote:

On Sat, 19 Aug 2006, Paul wrote:

   @@cachedDescr = {}

If you think reloading is happening, try:

@@cacheDescr = {} unless @@cacheDescr

Kirk Haines

Hi Kirk,

I tried @@cacheDescr = {} unless @@cacheDescr but I get the same results. I
would expect the initialization of @@cacheDescr to take place when the .rb
package is loaded. I will keep playing with it and post a solution when I
figure it out.

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

You really, really don't want to do this. Trust me. :wink:

You've already noted that this makes development mode suck. If you go this way, you will need to toggle the setting every time you need it to work or go without Rails's best development feature. Ouch.

That should be reason enough, but it gets worse!

Depending on how you deploy your application, it's quite likely you could have two or more separate interpreters running your production code. These will *not* share class variables. This is the way of pain and could be a source of all kinds of nasty issues.

If you need to remember a value in Rails it needs to be in the database or the session.

James Edward Gray II

···

On Aug 18, 2006, at 9:05 PM, Paul wrote:

To keep rails from reloading the class every time you
can change the ..\config\environments\development.rd file.

or you need to configure your app so that only one instance will run at once -
assuming fcgi execution. this is actually an easy solution for some simple
apps. however, james is quite correct.

-a

···

On Sat, 19 Aug 2006, James Edward Gray II wrote:

If you need to remember a value in Rails it needs to be in the database or
the session.

--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dali lama

James,

Thanks for the comments. I am coming from a Smalltalk background and we
would typically cache code/description lookup table rows into a class
variable for performance. That is, when we wanted to look up a
description we would check the cache first and then hit the database
only if it had not been retrieved yet.

In this scenario, it's not a problem if the cache is maintained
individually over separate instances of the interpreter. This way every
user benefits from the cache rather than storing it in a session unless
I misunderstand the life cycle of class variables. I would think they
would live until the class is reloaded.

However, I do see your point and agree and that under most application
situations this would not be the way to go.

Thanks,
Paul

James Edward Gray II wrote:

···

On Aug 18, 2006, at 9:05 PM, Paul wrote:

> To keep rails from reloading the class every time you
> can change the ..\config\environments\development.rd file.

You really, really don't want to do this. Trust me. :wink:

You've already noted that this makes development mode suck. If you
go this way, you will need to toggle the setting every time you need
it to work or go without Rails's best development feature. Ouch.

That should be reason enough, but it gets worse!

Depending on how you deploy your application, it's quite likely you
could have two or more separate interpreters running your production
code. These will *not* share class variables. This is the way of
pain and could be a source of all kinds of nasty issues.

If you need to remember a value in Rails it needs to be in the
database or the session.

James Edward Gray II

Just a side note. It isn't necessary to use class variables to
accomplish your goal. A plain old instance variable of the class object
is just fine. I'm not a big fan of Ruby class variables. I think they
are often used simply because they are confused with instance variables
of a class object.

Gary Wright

···

On Aug 19, 2006, at 12:00 PM, Paul wrote:

Thanks for the comments. I am coming from a Smalltalk background and we
would typically cache code/description lookup table rows into a class
variable for performance.

This smells like premature optimization to me. You've timed it and it's too slow or you have users complaining about the speed? If not, I worry you might be complicating this before you need to.

You are right that in this case, it shouldn't hurt to use a class variable. It is a waste of memory though and you may not get great cache hit rates.

The right way to handle this is with Rails's cache support:

   http://api.rubyonrails.com/classes/ActionController/Caching.html

This should be faster and more natural to implement, since you can develop normally and then apply caching as needed. It will also work across interpreters.

I'm not trying to tell you how to run your site. I hope it doesn't sound like I am. I'm just trying to help you avoid choices I'm pretty sure you will regret down the road.

Best of luck with your site.

James Edward Gray II

···

On Aug 19, 2006, at 11:00 AM, Paul wrote:

I am coming from a Smalltalk background and we
would typically cache code/description lookup table rows into a class
variable for performance. That is, when we wanted to look up a
description we would check the cache first and then hit the database
only if it had not been retrieved yet.

Hi Gary,

I'm not quite sure what you mean by using "an instance variable of the
class object". I am familiar with class variables and instance
variables. In my case I wanted to cache the data in a class variable
because *any* instance could reference the single class variable. Is
there yet another type of variable (other than temporary method scope
variables) that one could define?

Thanks,
Paul

gwtmp01@mac.com wrote:

···

On Aug 19, 2006, at 12:00 PM, Paul wrote:
> Thanks for the comments. I am coming from a Smalltalk background
> and we
> would typically cache code/description lookup table rows into a class
> variable for performance.

Just a side note. It isn't necessary to use class variables to
accomplish your goal. A plain old instance variable of the class object
is just fine. I'm not a big fan of Ruby class variables. I think they
are often used simply because they are confused with instance variables
of a class object.

Gary Wright

Hi James,

I do appreciate your comments and I was not aware of the caching
capabilities built into rails. I will take a look into the link you
provided to see how I can utilize this built in support.

Thanks again,
Paul

James Edward Gray II wrote:

···

On Aug 19, 2006, at 11:00 AM, Paul wrote:

> I am coming from a Smalltalk background and we
> would typically cache code/description lookup table rows into a class
> variable for performance. That is, when we wanted to look up a
> description we would check the cache first and then hit the database
> only if it had not been retrieved yet.

This smells like premature optimization to me. You've timed it and
it's too slow or you have users complaining about the speed? If not,
I worry you might be complicating this before you need to.

You are right that in this case, it shouldn't hurt to use a class
variable. It is a waste of memory though and you may not get great
cache hit rates.

The right way to handle this is with Rails's cache support:

   http://api.rubyonrails.com/classes/ActionController/Caching.html

This should be faster and more natural to implement, since you can
develop normally and then apply caching as needed. It will also work
across interpreters.

I'm not trying to tell you how to run your site. I hope it doesn't
sound like I am. I'm just trying to help you avoid choices I'm
pretty sure you will regret down the road.

Best of luck with your site.

James Edward Gray II

This is getting more into rails-talk, but just fyi - the built in
caching support doesn't really help with things like look up tables.
All the rails caching is based on the view level - actions, pages, and
fragmets. If you want to cache models, which is ideal for things like
look up tables, you could look into something like cached_model, which
uses memcached for its cache. Assuming its really a concern, you've
profiled, etc...

more info here:
http://nubyonrails.com/articles/2006/08/17/memcached-basics-for-rails

- Rob

···

On 8/19/06, Paul <prcorcoran@comcast.net> wrote:

Hi James,

I do appreciate your comments and I was not aware of the caching
capabilities built into rails. I will take a look into the link you
provided to see how I can utilize this built in support.

Thanks again,
Paul

--
http://www.robsanheim.com


http://www.ajaxian.com

This comes from Ruby's object model (and this may sound familiar to
you as a smalltalker): in Ruby, everything is an object, so any class
is an object as well. A class is an instance of class Class. Therefore
any class can have its instance variables (because it is an object) in
addition to class variables (class' special behaviour).

Class variables (@@variable) are shared among all sublasses of the class.

Class instance variables are those, that are defined in class methods i.e.

class A
  def self.m()
     @a = 1 # <- HERE!
  end
end

or:

class A
  class << self
    def m()
        @a = 1 # <- HERE!
    end
  end
end

These are not shared among subclasses.

HTH,
J.

···

On 8/19/06, Paul <prcorcoran@comcast.net> wrote:

Hi Gary,

I'm not quite sure what you mean by using "an instance variable of the
class object". I am familiar with class variables and instance
variables. In my case I wanted to cache the data in a class variable
because *any* instance could reference the single class variable. Is
there yet another type of variable (other than temporary method scope
variables) that one could define?

Thanks,
Paul

Smalltalk has pretty much the same thing, there's a difference between
class variables which are shared by the class and it's subclasses, and
are traditionally implemented by binding an association between the
name and value into compiled methods, and class instance variables
which are instance variables of the class object, and are implemented
as instance variable slots in the class objects, so every subclass has
it's own value. It's been awhile, and there are Smalltalk dialect
differences but these get declared in messages to the classes subclass
something like:

    Object subclass: #Foo ...
                instanceVariables: 'a b'
                classVariables: 'C1 C2'
                classInstanceVariables: 'ci1 ci2'

We also worked on a completely declarative model for class definition
in Smalltalk in X3J20, but I don't know if anyone picked it up.

In Ruby these are defined as they are encountered in execution and
marked with sigils, @ for instance and class variables, and @@ for
class variables, the difference between instance and class instance
variables being WHERE they are encountered.

In Smaltalk, class variables are in the scope of both class and
methods of the class which declares them, and its subclasses.
Instance variables are visible in methods of the class and it's
subclasses, and class instance variables to class methods of the class
and it's subclasses. This the same as in Ruby.

Getting back to the original question about caching. It seems to me
that one of the differences between Ruby and Smalltalk in their
'traditional' settings which affects the use of patterns such as using
class variables as a cache is that the Smalltalk execution environment
is usually a long-lived object memory, sometimes even with
'reincarnation' if the image is saved, while the Ruby environment
usually gets set up, runs a while and then gets destroyed. In a
server environment like rails, the lifecycle and even the number of
instances of the Ruby environment is configured during deployment, so
it's best if application code doesn't depend on a particular
lifecycle, or that application instances can communicate via classes
because they might not share the same class objects.

Smalltalkers who worked in transactional environments like MVS
Smalltalk running under CICS probably are more attuned to such
considerations.

···

On 8/19/06, Paul <prcorcoran@comcast.net> wrote:

Hi Gary,

I'm not quite sure what you mean by using "an instance variable of the
class object". I am familiar with class variables and instance
variables. In my case I wanted to cache the data in a class variable
because *any* instance could reference the single class variable. Is
there yet another type of variable (other than temporary method scope
variables) that one could define?

--
Rick DeNatale
http://talklikeaduck.denhaven2.com

Hi --

Hi Gary,

I'm not quite sure what you mean by using "an instance variable of the
class object". I am familiar with class variables and instance
variables. In my case I wanted to cache the data in a class variable
because *any* instance could reference the single class variable. Is
there yet another type of variable (other than temporary method scope
variables) that one could define?

Thanks,
Paul

This comes from Ruby's object model (and this may sound familiar to
you as a smalltalker): in Ruby, everything is an object, so any class
is an object as well. A class is an instance of class Class. Therefore
any class can have its instance variables (because it is an object) in
addition to class variables (class' special behaviour).

Class variables (@@variable) are shared among all sublasses of the class.

Class instance variables are those, that are defined in class methods i.e.

class A
def self.m()
   @a = 1 # <- HERE!
end

or:

class A
class << self
  def m()
      @a = 1 # <- HERE!
  end
end

These are not shared among subclasses.

Just one additional comment: you'll also see instance variables of
class objects outside of any method definition, like this:

   class C
     @var = 1
   end

etc. Every instance variable belongs to 'self' -- so whenever 'self'
is a class, you're seeing instance variables that belong to that
class.

David

···

On Sun, 20 Aug 2006, Jan Svitok wrote:

On 8/19/06, Paul <prcorcoran@comcast.net> wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
   ----> SEE SPECIAL DEAL FOR RUBY/RAILS USERS GROUPS! <-----
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
http://www.manning.com/black => book, Ruby for Rails
http://www.rubycentral.org => Ruby Central, Inc.

Jan and David:

Yes, this makes perfect sense now that you mention it. I had not seen
anything written up on it yet. Thanks for the examples.

Paul

Jan Svitok wrote:

···

On 8/19/06, Paul <prcorcoran@comcast.net> wrote:
> Hi Gary,
>
> I'm not quite sure what you mean by using "an instance variable of the
> class object". I am familiar with class variables and instance
> variables. In my case I wanted to cache the data in a class variable
> because *any* instance could reference the single class variable. Is
> there yet another type of variable (other than temporary method scope
> variables) that one could define?
>
> Thanks,
> Paul

This comes from Ruby's object model (and this may sound familiar to
you as a smalltalker): in Ruby, everything is an object, so any class
is an object as well. A class is an instance of class Class. Therefore
any class can have its instance variables (because it is an object) in
addition to class variables (class' special behaviour).

Class variables (@@variable) are shared among all sublasses of the class.

Class instance variables are those, that are defined in class methods i.e.

class A
  def self.m()
     @a = 1 # <- HERE!
  end
end

or:

class A
  class << self
    def m()
        @a = 1 # <- HERE!
    end
  end
end

These are not shared among subclasses.

HTH,
J.

Hi Rob,

Yes, MemCache looks like what I am after. Right now I'm doing
development on Windows XP and MemCache looks like it only runs on *nix.
When I have the environment to run it on I will certainly check this
out.

Thanks,
Paul

Rob Sanheim wrote:

···

On 8/19/06, Paul <prcorcoran@comcast.net> wrote:
> Hi James,
>
> I do appreciate your comments and I was not aware of the caching
> capabilities built into rails. I will take a look into the link you
> provided to see how I can utilize this built in support.
>
> Thanks again,
> Paul

This is getting more into rails-talk, but just fyi - the built in
caching support doesn't really help with things like look up tables.
All the rails caching is based on the view level - actions, pages, and
fragmets. If you want to cache models, which is ideal for things like
look up tables, you could look into something like cached_model, which
uses memcached for its cache. Assuming its really a concern, you've
profiled, etc...

more info here:
http://nubyonrails.com/articles/2006/08/17/memcached-basics-for-rails

- Rob

--
http://www.robsanheim.com
http://www.seekingalpha.com
http://www.ajaxian.com