[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Inheritance of class variables

Eustaquio Rangel de Oliveira Jr.

12/30/2004 1:17:00 PM

Hello there.

I was talking with chris2 and matju on the irc channel and they gave me
good explanation about this point, but I'd like to share it with you and
discuss something about it.

I was asking about if, when defined on a parent class, a class variable
overwrites the class variables with the same name on it's children.

For example:

------------------------------------------------------------------------
class CarBuilder
@@total_of_cars=0
def initialize(name)
@name = name
end
def build
puts "#{@name} building another car ..."
@@total_of_cars +=1
end
def total_of_cars
"#{@name} built #{@@total_of_cars} cars"
end
end

class Honda < CarBuilder
@@total_of_cars=0
def initialize
super("Honda")
end
end

class Ford < CarBuilder
@@total_of_cars=0
def initialize
super("Ford")
end
end

h = Honda::new
f = Ford::new

puts h.total_of_cars
puts f.total_of_cars

h.build
h.build
h.build
f.build

puts h.total_of_cars
puts f.total_of_cars
------------------------------------------------------------------------

Running this code we have:

------------------------------------------------------------------------
Honda built 0 cars
Ford built 0 cars
Honda building another car ...
Honda building another car ...
Honda building another car ...
Ford building another car ...
Honda built 4 cars
Ford built 4 cars
------------------------------------------------------------------------

So, there is a mistake here. Honda built 3 cars and Ford 1, and not 4 for
Honda and 4 for Ford. They are sharing the parent class variable, not
matter if it was defined on the children also.

Matsu told me that who came first is the boss, so if @@total_of_cars was
defined on the parent, not matter what, all the other children will refer
to it. I can live with that making some hacks ehehe but let me see:

------------------------------------------------------------------------
class CarBuilder
def initialize(name)
@name = name
end
def build
puts "#{@name} building another car ..."
increase
end
def increase
end
end

class Honda < CarBuilder
@@total_of_cars=0
def initialize
super("Honda")
end
def increase
@@total_of_cars +=1
end
def total_of_cars
"#{@name} built #{@@total_of_cars} cars"
end
end

class Ford < CarBuilder
@@total_of_cars=0
def initialize
super("Ford")
end
def increase
@@total_of_cars +=1
end
def total_of_cars
"#{@name} built #{@@total_of_cars} cars"
end
end

h = Honda::new
f = Ford::new

puts h.total_of_cars
puts f.total_of_cars

h.build
h.build
h.build
f.build

puts h.total_of_cars
puts f.total_of_cars
------------------------------------------------------------------------

Running it I got:

------------------------------------------------------------------------
Honda built 0 cars
Ford built 0 cars
Honda building another car ...
Honda building another car ...
Honda building another car ...
Ford building another car ...
Honda built 3 cars
Ford built 1 cars
------------------------------------------------------------------------

That is the correct behaviour.
But let check what I changed there on the code:

- I removed @@total_of_cars from CarBuilder, and put it on *each* child
class (there was one row of code, now there is two - or more, if more
children), and could be a problem if I miss the point on some child class
and forget to declare that variable there).

- On the CarBuilder, I create an empty method there called "increase" just
to call it on the "build" method (that I want the children inherit it's
funcionality). Two more rows there.

- I also removed the total_of_cars method from CarBuilder, but needed to
write it on each children. 3 rows less on the parent, but 3 more on each child.

- Also on the children I needed to write the increase method, 3 more rows
on each child.

Sorry if I'm missing some point here, because I'm a Ruby newbie, but is
that correct? I mean, seems that we need to write more code with this kind
of behaviour.

And if we forget to implement some of the needed methods or the
@@total_of_cars on each CarBuilder child (CarBuilder could have a lot of
other methods that I could want to inherit also!), it could not work normally.

On another point, if all this methods and variables could be inherited from
the parent class, will be no problem.

I don't really know if there is a strong and well-defined OOP concept on
the fact that a child cannot overwrite it's parent class variables, but
could you

- Tell me if there is some kind of OOP concept like that and
- Tell me if the way I made the code, even with more lines, is the correct
and more efficient way to control how many cars each CarBuilder child made?

Thanks for your attention. :-)

----------------------------
Eustáquio "TaQ" Rangel
eustaquiorangel@yahoo.com
http://b...
Usuário GNU/Linux no. 224050


21 Answers

David Heinemeier Hansson

12/30/2004 1:29:00 PM

0

> Sorry if I'm missing some point here, because I'm a Ruby newbie, but
> is that correct? I mean, seems that we need to write more code with
> this kind of behaviour.

I was quite puzzled by this behavior too. So in Rails I use a module
called class_inheritable_attributes.rb. It's a bit inconvenient, but I
usually wrap all calls to this lib in pretty accessors anyway, so it's
not that big of a deal. And very helpful :)

http://dev.rubyonrails.com/file/trunk/activesu...
class_inheritable_attributes.rb
--
David Heinemeier Hansson,
http://www.basec... -- Web-based Project Management
http://www.rubyon... -- Web-application framework for Ruby
http://macro... -- TextMate: Code and markup editor (OS X)
http://www.loudthi... -- Broadcasting Brain



ts

12/30/2004 1:45:00 PM

0

>>>>> "E" == Eustaquio Rangel de Oliveira <eustaquiorangel@yahoo.com> writes:

E> Sorry if I'm missing some point here, because I'm a Ruby newbie, but is
E> that correct? I mean, seems that we need to write more code with this kind
E> of behaviour.

it's strange your model :-)))

class CarBuilder
def self.inherited(kl)
kl.instance_eval { @total_of_cars = 0 }
super
end

def build
puts "#{self.class} building another car ..."
self.class.instance_eval { @total_of_cars += 1 }
end

def total_of_cars
"#{self.class} built #{self.class.instance_eval { @total_of_cars }} cars"
end
end

class Honda < CarBuilder
end

class Ford < CarBuilder
end



Guy Decoux



Eustaquio Rangel de Oliveira Jr.

12/30/2004 1:59:00 PM

0

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

| it's strange your model :-)))

Hey Guy!

Thanks, it worked, but too much for a newbie, I need to take a look and
learn with this now. You scared me ahahah, I told you I was a newbie. :-)
I didn't know that there was "self" on Ruby, for example. :-)
And what about that instance_eval and inherited there? Ahhh. :-)

Thanks! :-)

|
| class CarBuilder
| def self.inherited(kl)
| kl.instance_eval { @total_of_cars = 0 }
| super
| end
|
| def build
| puts "#{self.class} building another car ..."
| self.class.instance_eval { @total_of_cars += 1 }
| end
|
| def total_of_cars
| "#{self.class} built #{self.class.instance_eval { @total_of_cars
}} cars"
| end
| end
|
| class Honda < CarBuilder
| end
|
| class Ford < CarBuilder
| end

- ----------------------------
Eustáquio "TaQ" Rangel
eustaquiorangel@yahoo.com
http://b...
Usuário GNU/Linux no. 224050
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail....

iD8DBQFB1Aokb6UiZnhJiLsRAs0oAKC2uZAh8MB2amkV96JtIqa3vgQ6xACfUn3Y
EV+7wuTrWDyD8tq1LxBaV9w=
=DDYu
-----END PGP SIGNATURE-----


Shashank Date

12/30/2004 2:13:00 PM

0

Eustaquio Rangel de Oliveira Jr. wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> | it's strange your model :-)))
>
> Hey Guy!
>
> Thanks, it worked, but too much for a newbie, I need to take a look and
> learn with this now. You scared me ahahah, I told you I was a newbie. :-)

No, you scared not only becuase you are newbie, but because you were
answered by Guy :-)

Keep working on Ruby for many more years and he will still scare you ;-)

> I didn't know that there was "self" on Ruby, for example. :-)
> And what about that instance_eval and inherited there? Ahhh. :-)
>
> Thanks! :-)

Have fun !
-- shanko

> |
> | class CarBuilder
> | def self.inherited(kl)
> | kl.instance_eval { @total_of_cars = 0 }
> | super
> | end
> |
> | def build
> | puts "#{self.class} building another car ..."
> | self.class.instance_eval { @total_of_cars += 1 }
> | end
> |
> | def total_of_cars
> | "#{self.class} built #{self.class.instance_eval { @total_of_cars
> }} cars"
> | end
> | end
> |
> | class Honda < CarBuilder
> | end
> |
> | class Ford < CarBuilder
> | end
>
> - ----------------------------
> Eustáquio "TaQ" Rangel
> eustaquiorangel@yahoo.com
> http://b...
> Usuário GNU/Linux no. 224050
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.2.6 (GNU/Linux)
> Comment: Using GnuPG with Thunderbird - http://enigmail....
>
> iD8DBQFB1Aokb6UiZnhJiLsRAs0oAKC2uZAh8MB2amkV96JtIqa3vgQ6xACfUn3Y
> EV+7wuTrWDyD8tq1LxBaV9w=
> =DDYu
> -----END PGP SIGNATURE-----
>
>

Eustaquio Rangel de Oliveira Jr.

12/30/2004 2:30:00 PM

0

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi!

|> No, you scared not only becuase you are newbie, but because you were
|> answered by Guy :-)
|> Keep working on Ruby for many more years and he will still scare you ;-)

So he's kind of a Ruby boogeyman??? :-D
Just kidding. :-D
Thanks for your help (my brain is still hot here).

- ----------------------------
Eustáquio "TaQ" Rangel
eustaquiorangel@yahoo.com
http://b...
Usuário GNU/Linux no. 224050
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail....

iD8DBQFB1BE2b6UiZnhJiLsRAtqXAKCHE/FyFRVNT4tnq8PSIK5GQnpImwCgsNUG
c6lJaB/sETEPKkIe00VbwBU=
=amdM
-----END PGP SIGNATURE-----


Ruth A. Kramer

12/30/2004 2:41:00 PM

0

Eustaquio Rangel de Oliveira Jr. wrote:
> Thanks for your help (my brain is still hot here).

My brain is not here either (I'm fighting a headache) and I didn't
carefully read the example code, but maybe the following will help (and
maybe it's way off base).

Ruby allows you to have class variables and instance variables. If you
have a class like cars (I didn't read the example closely at all) and
instances for Ford, Honda, ..., only one class variable will exist but
instance variables will exist for Ford, Honda, .... Thus, if, for
example, you want a total over all cars, you (with suitable coding) want
to use the class variable. If you want separate totals for Ford, Honda,
..., you want to use instance variables.

Going even further out on a limb (I'm a Ruby newbie too (and <sad
attempt at a joke warning>and if you don't like my ideas, you could say
goodbye, Ruby newbie, and even write a song about it</sad attempt at a
joke warning>)), IIRC, a class variable is prefixed with @@, and
something else (maybe instance variables?) are prefixed with @.

Randy Kramer


Eustaquio Rangel de Oliveira Jr.

12/30/2004 3:00:00 PM

0

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi!

| Going even further out on a limb (I'm a Ruby newbie too (and <sad
| attempt at a joke warning>and if you don't like my ideas, you could say
| goodbye, Ruby newbie, and even write a song about it</sad attempt at a
| joke warning>)), IIRC, a class variable is prefixed with @@, and
| something else (maybe instance variables?) are prefixed with @.

No need to say goodbye or write a song ahahah. :-)
After all, I play on a Thrash Metal band, and we'are not so good on sad
songs ehehe. :-)

Best regards,

- ----------------------------
Eustáquio "TaQ" Rangel
eustaquiorangel@yahoo.com
http://b...
Usuário GNU/Linux no. 224050
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail....

iD8DBQFB1BhDb6UiZnhJiLsRAmchAKCOfldehdbOugM2nwVmQ1xgKHZVWACfZwzi
12/52V+nKZ6VVx4G5+5zX8Y=
=Uv2S
-----END PGP SIGNATURE-----


Ruth A. Kramer

12/30/2004 4:32:00 PM

0

Eustaquio Rangel de Oliveira Jr. wrote:
> :-)

:-)


Robert Klemme

12/30/2004 5:15:00 PM

0


"Eustaquio Rangel de Oliveira Jr." <eustaquiorangel@yahoo.com> schrieb im
Newsbeitrag news:41D4003E.2060503@yahoo.com...
> Hello there.
>
> I was talking with chris2 and matju on the irc channel and they gave me
> good explanation about this point, but I'd like to share it with you and
> discuss something about it.
>
> I was asking about if, when defined on a parent class, a class variable
> overwrites the class variables with the same name on it's children.

The short answer is the one that David gave implicite: just don't use
them. IMHO you can safely ignore this language feature without loosing
much but gaining a lot (understandability of code etc.).

As Guy pointed out, you should really be counting the number of cars in
the individual car classes. That's what he's doing with his instance
variable accesses.

I would probably model your example completely different, because Honda
and Ford are really instances of CarBuilder not really sub classes. So
this is the result and suddenly we don't need class vars any more:

class CarBuilder
attr_reader :name, :total_of_cars

def initialize(name)
@name = name
@total_of_cars = 0
end

def build
puts "#{name} builds another car"
@total_of_cars += 1
end
end

h = CarBuilder.new "Honda"
f = CarBuilder.new "Ford"

h.total_of_cars
f.total_of_cars

h.build
h.build
h.build
f.build

h.total_of_cars
f.total_of_cars


?> h = CarBuilder.new "Honda"
=> #<CarBuilder:0x101865d0 @name="Honda", @total_of_cars=0>
>> f = CarBuilder.new "Ford"
=> #<CarBuilder:0x10183af8 @name="Ford", @total_of_cars=0>
>>
?> h.total_of_cars
=> 0
>> f.total_of_cars
=> 0
>>
?> h.build
Honda builds another car
=> 1
>> h.build
Honda builds another car
=> 2
>> h.build
Honda builds another car
=> 3
>> f.build
Ford builds another car
=> 1
>>
?> h.total_of_cars
=> 3
>> f.total_of_cars
=> 1

Regards

robert

Eustaquio Rangel de Oliveira Jr.

12/30/2004 5:24:00 PM

0

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi!

| I would probably model your example completely different, because Honda
| and Ford are really instances of CarBuilder not really sub classes. So
| this is the result and suddenly we don't need class vars any more:

Thanks for your example! I'm learning about Ruby and taking notes to make a
begginer's tutorial, so while the Guy example really help me to go deep
inside the Ruby depths and think about all that stuff there (wow Guy I was
really amazed with the concept of creating a instance variable there!),
your example is easier for newbies (like me, also) to understand.

Thanks!

- ----------------------------
Eustáquio "TaQ" Rangel
eustaquiorangel@yahoo.com
http://b...
Usuário GNU/Linux no. 224050
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail....

iD8DBQFB1Domb6UiZnhJiLsRAueNAJ9kh49S5orefWnjnGzUFApTTSf5fgCgso88
qCqJuWGtyKasJRhWZb0+154=
=9xCK
-----END PGP SIGNATURE-----