Sharing variables between classes and instances

L

Leon Bogaert

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
 
D

David A. Black

Hi --

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!
 
L

Leon Bogaert

David said:
Hi --

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!
 
A

Albert Schlef

btw, you can simply do @@var to have a var that is shared among objects
of the same class.
 
R

Rick DeNatale

David said:
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.
 
R

Rick DeNatale

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

ara.t.howard

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/
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top