Forum: Ruby simple subclass question

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
E1f43bafda26307a050d11902752b2a6?d=identicon&s=25 Ball, Donald A Jr (Library) (Guest)
on 2007-05-01 17:31
(Received via mailing list)
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
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-01 17:44
(Received via mailing list)
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
0158871402c1ecfa57952e8a379cfd10?d=identicon&s=25 Daniel Lucraft (lucraft)
on 2007-05-01 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
E1f43bafda26307a050d11902752b2a6?d=identicon&s=25 Ball, Donald A Jr (Library) (Guest)
on 2007-05-01 23:35
(Received via mailing list)
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
E1f43bafda26307a050d11902752b2a6?d=identicon&s=25 Ball, Donald A Jr (Library) (Guest)
on 2007-05-01 23:45
(Received via mailing list)
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
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-02 00:12
(Received via mailing list)
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
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2007-05-02 01:12
(Received via mailing list)
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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 David A. Black (Guest)
on 2007-05-02 01:27
(Received via mailing list)
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
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (Guest)
on 2007-05-02 07:38
(Received via mailing list)
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
7f891fbe8e3bae7f9fe375407ce90d9d?d=identicon&s=25 Harold Hausman (Guest)
on 2007-05-02 08:27
(Received via mailing list)
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/seeingMetacla...

hth,
-Harold
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-05-02 17:33
(Received via mailing list)
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/
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-02 17:47
(Received via mailing list)
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
E1f43bafda26307a050d11902752b2a6?d=identicon&s=25 Ball, Donald A Jr (Library) (Guest)
on 2007-05-02 19:09
(Received via mailing list)
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
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-02 20:49
(Received via mailing list)
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
E1f43bafda26307a050d11902752b2a6?d=identicon&s=25 Ball, Donald A Jr (Library) (Guest)
on 2007-05-02 20:58
(Received via mailing list)
>     ......
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
93d566cc26b230c553c197c4cd8ac6e4?d=identicon&s=25 Pit Capitain (Guest)
on 2007-05-02 22:11
(Received via mailing list)
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/attri...

Regards,
Pit
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-02 22:57
(Received via mailing list)
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
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 Gary Wright (Guest)
on 2007-05-03 06:44
(Received via mailing list)
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
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-03 06:57
(Received via mailing list)
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
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-05-03 14:05
(Received via mailing list)
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/
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-05-03 14:12
(Received via mailing list)
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/
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-04 12:28
(Received via mailing list)
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
1c0cd550766a3ee3e4a9c495926e4603?d=identicon&s=25 John Joyce (Guest)
on 2007-05-04 12:57
(Received via mailing list)
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.
This topic is locked and can not be replied to.