If I want a class and its children to have different values for the same class variables, how would I go about making that happen? - donald
on 01.05.2007 17:31
on 01.05.2007 17:44
On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote: > If I want a class and its children to have different values for the same > class variables, how would I go about making that happen? > > - donald > > Hi Donald, has been a long time... 504/4 > cat subclass-vars.rb && ruby subclass-vars.rb #!/usr/bin/ruby # vim: sts=2 sw=2 nu expandtab tw=0: # P = Class.new { @a = 42 } class << P attr_accessor :a end S = Class.new P puts P.a puts S.a S.a = 43 puts P.a puts S.a ------> 42 nil 42 43 Hopefully I understood what you wanted. Cheers Robert
on 01.05.2007 17:49
Ball, Donald A Jr (Library) wrote: > If I want a class and its children to have different values for the same > class variables, how would I go about making that happen? > > - donald Instead of: class A def A.var=(v) @@var = v end def A.var @@var end end class B < A end where A and B will share the class variable, use a class instance variable instead: class A def A.var=(v) @var = v end def A.var @var end end class B < A end where A and B will have different class instance variables. You can use the attr_accessor notation to create class instance variable getters and setters like this: class A class << self attr_accessor :var end end best, Dan
on 01.05.2007 23:35
Thanks to you and Robert for the quick answers. I think I get it now; I
was a little fuzzy on the notion of class instance variables before. I
now use a construct like so:
class A
class << self
attr_accessor :var
end
end
class B < A
class << self
def var
@var || superclass.var
end
end
end
to allow subclasses's instance variables to default to their
superclass's until and unless overridden. I'll admit the class << self
syntax continues to mystify somewhat; can anyone proffer an explanation
that would help me grok it fully?
- donald
on 01.05.2007 23:45
Actually, I spoke too quickly. If I use this construct: > end > end > end How can I initialize var in A? I've tried: class A class << self @var = 'foo' attr_accessor :var end end to no avail. Also tried doing it in an initialize method. I'm still missing something key, I think. - donald
on 02.05.2007 00:12
On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote: > class B < A > class << self > def var > @var || superclass.var > end > end > end > > to allow subclasses's instance variables to default to their > superclass's until and unless overridden. That was the point I missed, but of course you did that nicely :). I'll admit the class << self > syntax continues to mystify somewhat; can anyone proffer an explanation > that would help me grok it fully? I will take a chance by saying that class << A def x... end end is the same as class A def self.x end end although there might be some subtle differences Do e.g, this class << A puts self end you can see kind of a Proxy object, but it behaves pretty much transparently. Cheers Robert
on 02.05.2007 01:12
On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov>
wrote:
> missing something key, I think.
class A
@var = 'foo'
class << self
attr_accessor :var
end
end
(warning, the following explanation is not really correct)
class << self is sort of A's class (the class of the class) (It's
actually
A's singleton class). By putting @var='foo' inside class << self you set
the
class of A's instance var @var to 'foo' not A's @var to foo.
- donald
on 02.05.2007 01:27
Hi -- On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote: > class B < A > that would help me grok it fully? Possibly; have a look at: http://www.rubypal.com/singletons.html David
on 02.05.2007 07:38
On Wed, May 02, 2007 at 06:33:57AM +0900, Ball, Donald A Jr (Library) wrote: > I'll admit the class << self > syntax continues to mystify somewhat; can anyone proffer an explanation > that would help me grok it fully? http://www.rubygarden.org/ruby?SingletonTutorial
on 02.05.2007 08:27
On 5/2/07, Brian Candler <B.Candler@pobox.com> wrote: > On Wed, May 02, 2007 at 06:33:57AM +0900, Ball, Donald A Jr (Library) wrote: > > I'll admit the class << self > > syntax continues to mystify somewhat; can anyone proffer an explanation > > that would help me grok it fully? > > http://www.rubygarden.org/ruby?SingletonTutorial > > I always liked this explanation: http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html hth, -Harold
on 02.05.2007 17:33
On 5/1/07, Logan Capaldo <logancapaldo@gmail.com> wrote: > > to no avail. Also tried doing it in an initialize method. I'm still > (warning, the following explanation is not really correct) > class << self is sort of A's class (the class of the class) (It's actually > A's singleton class). By putting @var='foo' inside class << self you set the > class of A's instance var @var to 'foo' not A's @var to foo. Going a little further in answering Donald's question. Instance variables come into being when they are initialized by code running in the context of the instance. Usually that's method code. This works in the case of class methods, class instance variables are just instance variables of the class. However since, I think what we are looking for is a way to initialize class instance variables in a way analogous to class variables, we really don't always want to define a method. Here's one way to accomplish class instance variable intialization in-line in a class (re)definition. class A instance_eval {@var = 'foo'} class << self attr_accessor :var end end since within the class (re)definition self IS the class, instance_eval runs the block in the context of the class. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
on 02.05.2007 17:47
On 5/2/07, Rick DeNatale <rick.denatale@gmail.com> wrote: <snip> > > class A > instance_eval {@var = 'foo'} I guess I lost you here Rick, is this for didactic purpose, or am I wrong by saying that instance_eval { @var = 'foo' } is *exactly* the same as @var = 'foo' .... <snip> Cheers Robert
on 02.05.2007 19:09
Okay, so maybe this turns out to be a not-so-simple subclass question
after all. I appreciate all the thoughtful answers and links, I'm pretty
close to wrapping my head around it all. I'm still having trouble with
class instance variable initialization, and have come up with code
sample which should illustrate the point:
class Breakfast
def self.add_food(*args)
@foods ||= []
args.each do |arg|
@foods << arg
end
end
def self.foods
if superclass.respond_to?(:foods)
superclass.foods + @foods
else
@foods
end
end
add_food :eggs
end
class RubyBreakfast < Breakfast
add_food :grapefruit, :chunky_bacon
end
class BoringBreakfast < Breakfast
add_food :dry_toast, :gruel
end
Everybody loves breakfast, right? This code works great, except... maybe
I don't want Breakfast to have :eggs by default, but if I remove the
add_food :eggs from Breakfast, then Breakfast.foods returns nil instead
of [] since @foods isn't initialized until add_food is called, and
RubyBreakfast.foods throws an exception trying to its delicious foods
array to nil. But I'll be damned if I can figure out how to properly
initialize @foods in Breakfast. Can someone point me in the proper
direction?
- donald
on 02.05.2007 20:49
On 5/2/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote: > Okay, so maybe this turns out to be a not-so-simple subclass question > after all. I appreciate all the thoughtful answers and links, I'm pretty > close to wrapping my head around it all. I'm still having trouble with > class instance variable initialization, and have come up with code > sample which should illustrate the point: > > class Breakfast > def self.add_food(*args) > @foods ||= [] just initialize @foods in the class class Breakfast @foods = [] # class instance variable, I did this in my original example # because of (1) def self.add_food( *args) @foods += args end ...... <snip> > Everybody loves breakfast, right? This code works great, except... maybe > I don't want Breakfast to have :eggs by default, but if I remove the > add_food :eggs from Breakfast, then Breakfast.foods returns nil instead > of [] since @foods isn't initialized until add_food is called, and > RubyBreakfast.foods throws an exception trying to its delicious foods > array to nil. But I'll be damned if I can figure out how to properly > initialize @foods in Breakfast. Can someone point me in the proper > direction? Hopefully I did, if not continue asking I am a bad teacher, I know :(. (1) class A @cl_inst_var = 42 end is the same (unless class A has been defined before) as A = Class.new { @cl_inst_var = 42 } Cheers Robert
on 02.05.2007 20:58
> ......
but then @foods doesn't exist in RubyBreakfast and BoringBreakfast. I
mean, sure, I could cut'n'paste @foods = [] in each of them, but that
doesn't smell right. In the superclass, I want a chunk of code that
initializes a class instance variable in itself and each of its class
descendents.
In point of fact, I can work around the @foods.nil? case in the
self.foods method, but I'd rather figure out either how to do this or
why it's a bad idea to do it. :)
- donald
on 02.05.2007 22:11
Ball, Donald A Jr (Library) schrieb: > In point of fact, I can work around the @foods.nil? case in the > self.foods method, but I'd rather figure out either how to do this or > why it's a bad idea to do it. :) Donald, I would add def self.my_foods @foods ||= [] end and then use my_foods instead of @foods in the other two methods. You could also take a look at Ara's attributes library: http://codeforpeople.com/lib/ruby/attributes/attributes-3.2.0/README Regards, Pit
on 02.05.2007 22:57
On 5/2/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote: > > ...... > > but then @foods doesn't exist in RubyBreakfast and BoringBreakfast. I > mean, sure, I could cut'n'paste @foods = [] in each of them, but that > doesn't smell right. In the superclass, I want a chunk of code that > initializes a class instance variable in itself and each of its class > descendents. You mean you want to have your cake *and* eat it ;)? Sure enough, but there is no simple solution, you could do something like this class Module def inherit_cl_inst_vars # refinement via args as you wish superclass.instance_variables.each do | ivar | instance_variable_set ivar, superclass.instance_variable_get( ivar ) end end end class A @a = 42 end class B < A inherit_cl_inst_vars end class << A attr_accessor :a end puts A.a puts B.a B.a=1764 puts A.a puts B.a > > In point of fact, I can work around the @foods.nil? case in the > self.foods method, but I'd rather figure out either how to do this or > why it's a bad idea to do it. :) > > - donald > > Robert
on 03.05.2007 06:44
On May 2, 2007, at 2:57 PM, Ball, Donald A Jr (Library) wrote: > In the superclass, I want a chunk of code that > initializes a class instance variable in itself and each of its class > descendents. You can use #inherited to trigger your own class initialization: class Base class <<self def inherited(other) other.instance_eval { initialize_class } end def initialize_class @foo = 42 end attr_accessor :foo end initialize_class end class Subclass < Base puts "foo is #{@foo}" # 42 end puts Subclass.foo # 42 puts Class.new(Base).foo # 42 Gary Wright
on 03.05.2007 06:57
On 5/3/07, Gary Wright <gwtmp01@mac.com> wrote: > def inherited(other) > class Subclass < Base > puts "foo is #{@foo}" # 42 > end > > puts Subclass.foo # 42 > puts Class.new(Base).foo # 42 > > > > Gary Wright Wow that scales much better than mine Gary, nice. However maybe you want to inherit @foo dynamically, that is I suggest this slight adaptation of Base 529/29 > cat inherited.rb && ruby inherited.rb # vim: sts=2 sw=2 expandtab tw=0 nu: class Base @foo = 42 class <<self def inherited(other) other.instance_eval { initialize_class } end def initialize_class @foo = superclass.instance_variable_get("@foo") end attr_accessor :foo end end class Subclass < Base puts "Sub foo is #{@foo}" # 42 end Base.foo = 1764 class Another < Base puts "Another foo is #{@foo}" # 42 end puts Subclass.foo # 42 puts Class.new(Base).foo # 42 Sub foo is 42 Another foo is 1764 42 1764 What do you think, anyway the two behaviors might be what you want, I actually need the second behavior. Cheers Robert
on 03.05.2007 14:05
On 5/2/07, Robert Dober <robert.dober@gmail.com> wrote: > is *exactly* the same as > > @var = 'foo' > > .... > <snip> D'oh! You're right of course. It's like those times when I ask my wife if she's seen my eyeglasses and she tells me that I'm wearing them! -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
on 03.05.2007 14:12
On 5/2/07, Robert Dober <robert.dober@gmail.com> wrote: > You mean you want to have your cake *and* eat it ;)? Actually, this is no problem at all, in fact you have to have your cake before you eat it. The trick is to eat your cake and have it too. Almost everyone gets this old saying backwards. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
on 04.05.2007 12:28
On 5/3/07, Rick DeNatale <rick.denatale@gmail.com> wrote: > On 5/2/07, Robert Dober <robert.dober@gmail.com> wrote: > > > You mean you want to have your cake *and* eat it ;)? > > Actually, this is no problem at all, in fact you have to have your > cake before you eat it. > > The trick is to eat your cake and have it too. > > Almost everyone gets this old saying backwards. As the English language is the greatest victim of trivialization by foreign speakers and writers I appreciate enormously to get these things right. It is a great irony that countries like France, where I happen to live, are very worried about the influence of English - and they are right because I do not feel that English verbs scale very nicely into latin languages but this is beyond my point. The true "victim" of English's globalization is English itself. But that is how languages have evolved for millennia now and there is nothing we can do about it. (Imagine the shock Sallust, Cicero or Caesar would have had when hearing the vulgo from of Latin that gave birth to latin languages). But I do not like it nonetheless. Cheers Robert
on 04.05.2007 12:57
On May 4, 2007, at 7:27 PM, Robert Dober wrote: >> Almost everyone gets this old saying backwards. > nothing we can do about it. (Imagine the shock Sallust, Cicero or > Caesar would have had when hearing the vulgo from of Latin that gave > birth to latin languages). This is OT. But I'll bite. Utter nonsense. Languages are never victims. No human language is canonical. It isn't possible. English is one of the few languages whose grammar books are not dictated by committee, but updated to reflect modern usage. English, like all human languages is flexible and fuzzy. Now the number of speakers of English as a second language outnumber native English speakers. This simply means that English now has more dialects than ever and where they all overlap is where you will find the language. Language and culture are often difficult to separate and thus societies attempt to preserve something that is intangible. Language and culture are organic and depend on each connection between individuals to identify what is and is not functioning symbolic code for communication of ideas. Language is its own disruptive technology. It contradicts, counteracts and alters itself. Often words do or eventually will have exactly opposite or wholly different meanings from their origins. English has no foreign speakers. English has no single country or nation. It has always historically been a mix-in. There is not and never has been such a concept as a pure language. Thus, nobody is trivializing any language. Native speakers of any given language will often and naturally take it for granted. Sallust, Cicero and Caesar would hardly have been shocked by Latin pidgins and creoles. Those existed in their time. It was always an effect of expansion of communication and interaction, all provided primarily by advancing and spreading technology (roads, writing, commerce) and a little dash of imperialism to boot.