Sharing variables between classes and instances

Discussion in 'Ruby' started by Leon Bogaert, May 11, 2008.

  1. Leon Bogaert

    Leon Bogaert Guest

    Hi all,

    What I'm trying to achieve: add a variable to a class. Fill it with
    data. Every nstance of that class should have access to the data in that
    variable. But I want every instance be able to modify that variable,
    without modifying the original value of the variable.

    It's like adding methods to the singleton class of an instance (if I
    explain it properly).

    I think it becomes a lot clearer if you see the code I've written:
    http://pastie.caboo.se/194982

    I thought this guy described what I needed:
    http://briancarper.net/2007/03/22/ruby-singleton-classes/
    But even then I can't get it to work.

    Thanks in advance!
    Leon
    --
    Posted via http://www.ruby-forum.com/.
     
    Leon Bogaert, May 11, 2008
    #1
    1. Advertising

  2. Hi --

    On Sun, 11 May 2008, Leon Bogaert wrote:

    > Hi all,
    >
    > What I'm trying to achieve: add a variable to a class. Fill it with
    > data. Every nstance of that class should have access to the data in that
    > variable. But I want every instance be able to modify that variable,
    > without modifying the original value of the variable.


    I'm not sure what you mean exactly. Do you mean each instance should
    have a copy of the object? If so, I would just do:

    class Tester

    def self.vars
    @vars ||= []
    end

    def self.add_var(var)
    self.vars << var
    end

    def vars
    @vars || self.class.vars
    end

    def add_var(var)
    @vars ||= self.class.vars.dup
    vars << var
    end
    end

    That gives the results you expect in your test.


    David

    --
    Rails training from David A. Black and Ruby Power and Light:
    INTRO TO RAILS June 9-12 Berlin
    ADVANCING WITH RAILS June 16-19 Berlin
    INTRO TO RAILS June 24-27 London (Skills Matter)
    See http://www.rubypal.com for details and updates!
     
    David A. Black, May 11, 2008
    #2
    1. Advertising

  3. Leon Bogaert

    Leon Bogaert Guest

    David A. Black wrote:
    > Hi --
    >
    > On Sun, 11 May 2008, Leon Bogaert wrote:
    >
    >> Hi all,
    >>
    >> What I'm trying to achieve: add a variable to a class. Fill it with
    >> data. Every nstance of that class should have access to the data in that
    >> variable. But I want every instance be able to modify that variable,
    >> without modifying the original value of the variable.

    >
    > I'm not sure what you mean exactly. Do you mean each instance should
    > have a copy of the object? If so, I would just do:
    >
    > class Tester
    >
    > def self.vars
    > @vars ||= []
    > end
    >
    > def self.add_var(var)
    > self.vars << var
    > end
    >
    > def vars
    > @vars || self.class.vars
    > end
    >
    > def add_var(var)
    > @vars ||= self.class.vars.dup
    > vars << var
    > end
    > end
    >
    > That gives the results you expect in your test.
    >
    >
    > David


    Thanks David. That's a whole lot simpler. I think I'll stick with your
    example.
    Except I think I'll merge @vars & self.class.vars each time vars() gets
    called. So you can update the original Tester class with new vars and
    that the instances have access to these new vars too.

    Thanks!
    --
    Posted via http://www.ruby-forum.com/.
     
    Leon Bogaert, May 11, 2008
    #3
  4. btw, you can simply do @@var to have a var that is shared among objects
    of the same class.
    --
    Posted via http://www.ruby-forum.com/.
     
    Albert Schlef, May 11, 2008
    #4
  5. On Sun, May 11, 2008 at 8:33 AM, Leon Bogaert <> wrote:
    > David A. Black wrote:
    >> On Sun, 11 May 2008, Leon Bogaert wrote:


    >>> What I'm trying to achieve: add a variable to a class. Fill it with
    >>> data. Every nstance of that class should have access to the data in that
    >>> variable. But I want every instance be able to modify that variable,
    >>> without modifying the original value of the variable.


    >> I'm not sure what you mean exactly. Do you mean each instance should
    >> have a copy of the object? If so, I would just do:
    >>
    >> class Tester
    >>
    >> def self.vars
    >> @vars ||= []
    >> end
    >>
    >> def self.add_var(var)
    >> self.vars << var
    >> end
    >>
    >> def vars
    >> @vars || self.class.vars
    >> end
    >>
    >> def add_var(var)
    >> @vars ||= self.class.vars.dup
    >> vars << var
    >> end
    >> end
    >>
    >> That gives the results you expect in your test.



    > Thanks David. That's a whole lot simpler. I think I'll stick with your
    > example.
    > Except I think I'll merge @vars & self.class.vars each time vars() gets
    > called. So you can update the original Tester class with new vars and
    > that the instances have access to these new vars too.


    You might also want to have a look at the class_inheritable_accessor
    and related methods from the activesupport gem (part of Rails), which
    never seems to come up in similar threads on Ruby talk. It sort of
    does what you want, although it sets things up when a class is
    subclassed and doesn't keep up with changes.

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
     
    Rick DeNatale, May 11, 2008
    #5
  6. On Sun, May 11, 2008 at 10:09 AM, Albert Schlef <> wrote:
    > btw, you can simply do @@var to have a var that is shared among objects
    > of the same class.


    There be dragons! Class variables (@@var) in Ruby are also shared by
    subclasses (with some quirks in some cases such as when a superclass
    acquires a class variable AFTER one or more of its subclasses) and
    violate the expectations of almost everyone who tries to use them.

    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
     
    Rick DeNatale, May 11, 2008
    #6
  7. Leon Bogaert

    ara.t.howard Guest

    On May 10, 2008, at 6:40 PM, David A. Black wrote:
    >>
    >> Hi all,
    >>
    >> What I'm trying to achieve: add a variable to a class. Fill it with
    >> data. Every nstance of that class should have access to the data in
    >> that
    >> variable. But I want every instance be able to modify that variable,
    >> without modifying the original value of the variable.

    >
    > I'm not sure what you mean exactly. Do you mean each instance should
    > have a copy of the object? If so, I would just do:
    >
    > class Tester
    >
    > def self.vars
    > @vars ||= []
    > end
    >
    > def self.add_var(var)
    > self.vars << var
    > end
    >
    > def vars
    > @vars || self.class.vars
    > end
    >
    > def add_var(var)
    > @vars ||= self.class.vars.dup
    > vars << var
    > end
    > end
    >
    > That gives the results you expect in your test.
    >




    careful, any ruby code that uses 'dup' or clone has serious bugs 9 out
    of 10 times, in the case it doesn't meet the OP's *requirements*
    (although the simple test case passes) at all:

    cfp:~ > cat a.rb
    #
    # doesn't let instance modify the var without modifying the class var
    #

    Tester.add_var 'oops'
    t = Tester.new
    t.vars.first << ', this modifies the original'
    p Tester.vars #=> "oops, this modifies the original"


    #
    # and doesn't take a copy either
    #
    Tester.vars.clear
    Tester.add_var ['oops']
    t = Tester.new
    t.vars.first << ', this modifies the original'
    p Tester.vars #=> [["oops", ", this modifies the original"]]


    BEGIN {
    class Tester
    def self.vars
    @vars ||= []
    end

    def self.add_var(var)
    self.vars << var
    end

    def vars
    @vars || self.class.vars
    end

    def add_var(var)
    @vars ||= self.class.vars.dup
    vars << var
    end
    end
    }


    cfp:~ > ruby a.rb
    ["oops, this modifies the original"]
    [["oops", ", this modifies the original"]]




    you really need one of two things: a factory or a smarter copy
    algorithm:

    using a factory:

    cfp:~ > cat a.rb

    class Shares
    Factory = lambda { |var|
    case var.to_s
    when 'a'
    'not shared'
    when 'b'
    'but created fresh for class and instance cases'
    else
    end
    }

    def Shares.a
    @a ||= Factory['a']
    end

    def a
    @a ||= Factory['a']
    end
    end

    p Shares.a

    shares = Shares.new
    shares.a << ", but it's own copy"

    p Shares.a
    p shares.a


    cfp:~ > ruby a.rb
    "not shared"
    "not shared"
    "not shared, but it's own copy"



    or, using a smart copy method:

    cfp:~ > cat a.rb
    class Shares
    def Shares.a
    @a ||= 'not shared'
    end

    def a
    @a ||= Marshal.load(Marshal.dump(Shares.a))
    end
    end

    p Shares.a

    shares = Shares.new
    shares.a << ", but it's own copy"

    p Shares.a
    p shares.a


    cfp:~ > ruby a.rb
    "not shared"
    "not shared"
    "not shared, but it's own copy"


    this is nicer, but only works for objects you can marshal - obvisouly.


    a @ http://codeforpeople.com/
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
     
    ara.t.howard, May 11, 2008
    #7
    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. Replies:
    8
    Views:
    458
    Robbe Morris [C# MVP]
    Apr 5, 2006
  2. Replies:
    0
    Views:
    412
  3. Mike
    Replies:
    3
    Views:
    298
  4. Trevoke
    Replies:
    10
    Views:
    204
    Brian Candler
    Jul 22, 2009
  5. Derek Basch

    Sharing a socket between instances

    Derek Basch, Jul 31, 2006, in forum: Perl Misc
    Replies:
    5
    Views:
    158
Loading...

Share This Page