Class variables in Ruby

Discussion in 'Ruby' started by Paul, Aug 18, 2006.

  1. Paul

    Paul Guest

    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
     
    Paul, Aug 18, 2006
    #1
    1. Advertising

  2. Paul

    Guest

    On Sat, 19 Aug 2006, Paul wrote:

    > @@cachedDescr = {}


    If you think reloading is happening, try:

    @@cacheDescr = {} unless @@cacheDescr


    Kirk Haines
     
    , Aug 18, 2006
    #2
    1. Advertising

  3. Paul

    Daniel Waite Guest

    > @@cacheDescr = {} unless @@cacheDescr

    Or, to be more idiomatic:

    @@cache_descr ||= {}



    --
    Posted via http://www.ruby-forum.com/.
     
    Daniel Waite, Aug 18, 2006
    #3
  4. Paul

    Guest

    On Sat, 19 Aug 2006, Daniel Waite wrote:

    >> @@cacheDescr = {} unless @@cacheDescr

    >
    > Or, to be more idiomatic:
    >
    > @@cache_descr ||= {}


    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
     
    , Aug 18, 2006
    #4
  5. Paul

    Paul Guest

    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.

    Thanks,
    Paul
     
    Paul, Aug 18, 2006
    #5
  6. Paul

    Guest

    On Sat, 19 Aug 2006, Paul wrote:

    >
    > 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.


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

    -a
    --
    to foster inner awareness, introspection, and reasoning is more efficient than
    meditation and prayer.
    - h.h. the 14th dali lama
     
    , Aug 19, 2006
    #6
  7. Paul

    Paul Guest

    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.
     
    Paul, Aug 19, 2006
    #7
  8. 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. ;)

    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
     
    James Edward Gray II, Aug 19, 2006
    #8
  9. Paul

    Guest

    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.


    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
    --
    to foster inner awareness, introspection, and reasoning is more efficient than
    meditation and prayer.
    - h.h. the 14th dali lama
     
    , Aug 19, 2006
    #9
  10. Paul

    Paul Guest

    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. ;)
    >
    > 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
     
    Paul, Aug 19, 2006
    #10
  11. Paul

    Guest

    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
     
    , Aug 19, 2006
    #11
  12. 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
     
    James Edward Gray II, Aug 19, 2006
    #12
  13. Paul

    Paul Guest

    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

    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
     
    Paul, Aug 19, 2006
    #13
  14. Paul

    Paul Guest

    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
     
    Paul, Aug 19, 2006
    #14
  15. Paul

    Rob Sanheim Guest

    On 8/19/06, Paul <> 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
     
    Rob Sanheim, Aug 19, 2006
    #15
  16. Paul

    Jan Svitok Guest

    On 8/19/06, Paul <> 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.
     
    Jan Svitok, Aug 20, 2006
    #16
  17. Paul

    Guest

    Hi --

    On Sun, 20 Aug 2006, Jan Svitok wrote:

    > On 8/19/06, Paul <> 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.


    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

    --
    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.
     
    , Aug 20, 2006
    #17
  18. Paul

    Paul Guest

    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 <> 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.
     
    Paul, Aug 20, 2006
    #18
  19. Paul

    Paul Guest

    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 <> 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
     
    Paul, Aug 20, 2006
    #19
  20. On 8/19/06, Paul <> 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?


    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.


    --
    Rick DeNatale
    http://talklikeaduck.denhaven2.com
     
    Rick DeNatale, Aug 21, 2006
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. avnrao
    Replies:
    0
    Views:
    3,392
    avnrao
    May 7, 2004
  2. dwok
    Replies:
    7
    Views:
    720
    Hal Rosser
    Mar 4, 2005
  3. E11
    Replies:
    1
    Views:
    4,897
    Thomas Weidenfeller
    Oct 12, 2005
  4. Replies:
    9
    Views:
    995
  5. Ralph Shnelvar
    Replies:
    29
    Views:
    812
    David Masover
    Nov 30, 2009
Loading...

Share This Page