# Proper way to define a subclass within parent file?

**URL:** <https://www.ruby-forum.com/t/proper-way-to-define-a-subclass-within-parent-file/151990>\
**Category:** Ruby\
**Created:** [October 28, 2008, 6:57pm UTC](https://www.ruby-forum.com/t/proper-way-to-define-a-subclass-within-parent-file/151990 "2008-10-28T18:57:56Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![asherwood](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c67d28/32.png) [@asherwood](https://www.ruby-forum.com/u/asherwood)\
**Post date:** [October 28, 2008, 6:57pm UTC](https://www.ruby-forum.com/t/proper-way-to-define-a-subclass-within-parent-file/151990/1 "2008-10-28T18:57:56Z")

</div>

I am starting to build a script to manipulate various network device  
information, including a list of Vlans from a switch. To that end, I  
created a Vlan class:

class Vlan  
@@max = 399  
@@min = 1  
@@protected = [1,2,5]  
@@namelen = 32  
def initialize (id,desc)  
self.set\_name(desc) if (self.set\_id(id))  
end  
def set\_id (id)  
return nil unless (id.kind\_of? Integer)  
return nil if (@@protected.index(id) || id \> @@max || id \< @@min)  
@id = id  
end  
def set\_name (desc)  
desc.gsub!(/\s+/,"\_")  
desc = desc[0…@@namelen-1] if (desc.length \> @@namelen)  
@description = desc  
end  
def to\_s  
return “#{@id}\t#{@description}”  
end  
def valid?  
return true if (@id.kind\_of? Integer)  
return false  
end

# snip various other methods

end

This works as expected; to test it out I added some debugging code to  
loop through some values and verify it only created valid instances:

v = Array.new  
20.times { |a|  
temp = Vlan.new(a,“this is vlan id #{a}”)  
v.insert(-1,temp) if (temp.valid?)  
}  
v.length.times { |a| puts “#{a} #{v[a].to\_s}” }

I then added a simple subclass, within the same file. This special kind  
of Vlan acts like the others, except it uses a different range of valid  
id values:

class HMC\_Vlan \< Vlan  
@@min = 701  
@@max = 799  
@@protected = [700,705]  
end

I then added to the debug code:

v2 = Array.new  
700.upto(720) { |a|  
temp2 = HMC\_Vlan.new(a,“hmcvlan.#{a}”)  
v2.insert(-1,temp2) if (temp2.valid?)  
}  
v2.length.times { |a| puts “#{a} #{v2[a].to\_s}” }

When I ran this file, it created HMC\_Vlans as expected, but no longer  
created any valid Vlans (“v” array was empty). It turns out the class  
variables @@max, min, protected in HMC\_Vlan are overwriting the class  
variables in Vlan - even though no instance of HMC\_Vlan is created until  
after my debug code creates the “v” array.  
It was my understanding that a Class declaration was treated as a  
conditional block - _if_ someone creates this Class, _then_ run through  
the contents. But here it appears the class declaration is processed  
before any instance of it is made. Even so, shouldn’t a class variable  
be specific to that class, and not be shared with children? Is there  
another kind of inheritance I can use to maintain this separation in  
class variables? Is there a specific way to define a subclass within the  
same file as the parent? Why does the class HMC\_Vlan definition get  
executed before any instances are created?

I am running this under Windows (ActiveRuby 1.8.6)

---

<div class="post-metadata">

**Author:** ![asherwood](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c67d28/32.png) [@asherwood](https://www.ruby-forum.com/u/asherwood)\
**Post date:** [October 28, 2008, 8:32pm UTC](https://www.ruby-forum.com/t/proper-way-to-define-a-subclass-within-parent-file/151990/2 "2008-10-28T20:32:03Z")

</div>

Alle Tuesday 28 October 2008, Scott Strattner ha scritto:

> ```
> self.set_name(desc) if (self.set_id(id))
> 
> ```
> 
> end  
> This works as expected; to test it out I added some debugging code to  
> of Vlan acts like the others, except it uses a different range of valid  
> v2 = Array.new  
> after my debug code creates the “v” array.  
> It was my understanding that a Class declaration was treated as a  
> conditional block - _if_ someone creates this Class, _then_ run through  
> the contents.

You’re wrong here. The body of a class definition is executed when it’s  
found.  
Method bodies (for both instance methods and class methods) aren’t  
executed  
untill they’re called, but all the rest of the class body is executed  
immediately. For example, the code

class C

puts “body of class C”

def method1  
puts “body of method method1”  
end

end

when read produces the output

“body of class C”

and, after that, calling C.instance\_methods will return an array which  
contains the string “method1”, showing that the method method1 has  
already  
been defined. On the other hand, the body of method1 is only executed  
after a  
call to it, for example with the code C.new.method1.

> But here it appears the class declaration is processed  
> before any instance of it is made. Even so, shouldn’t a class variable  
> be specific to that class, and not be shared with children? Is there  
> another kind of inheritance I can use to maintain this separation in  
> class variables? Is there a specific way to define a subclass within the  
> same file as the parent?

Class variables are shared among a class and all its subclasses. If you  
don’t  
want that, you can use class instance variables, that is instance  
variables of  
the class object. They work like common instance variables, and can be  
accessed outside the class body only if appropriate class methods are  
defined  
(note: this is also true inside instance methods of the class). You  
could do  
this:

class Vlan  
@max = 399  
@min = 1  
@protected = [1,2,5]  
@namelen = 32

def self.max  
@max  
end

def self.min  
@min  
end

def self.protected  
@protected  
end

def set\_id (id)  
return nil unless (id.kind\_of? Integer)  
return nil if (self.class.protected.index(id) || id \>  
self.classl.max ||  
id \< self.class.min)  
@id = id  
end

…

The only problem with this approach is that all instance variables  
should be  
initialized in all classes which need them (you don’t need to redefine  
the  
methods, instead).

Another possibility, if the values in the instance variables shouldn’t  
change  
is to use constants:

class Vlan  
MAX = 399  
MIN = 1  
PROTECTED = [1,2,5]  
NAMELEN = 32

I hope this helps

Stefano

---

<div class="post-metadata">

**Author:** ![asherwood](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c67d28/32.png) [@asherwood](https://www.ruby-forum.com/u/asherwood)\
**Post date:** [October 28, 2008, 9:09pm UTC](https://www.ruby-forum.com/t/proper-way-to-define-a-subclass-within-parent-file/151990/3 "2008-10-28T21:09:00Z")

</div>

Stefano C. wrote:

> Class variables are shared among a class and all its subclasses. If you  
> don’t  
> want that, you can use class instance variables, that is instance  
> variables of  
> the class object.

I knew of instance variables, and class variables, but not class  
instance variables. It seems to do what I need, although the syntax will  
take some getting used to.

> Another possibility, if the values in the instance variables shouldn’t  
> change  
> is to use constants:

I originally had methods to modify these class variables, but I just  
tried using constants, and that worked. So I will probably create a  
subclass for every kind of VLAN encountered (which will then define the  
constant values for that particular subclass).

> I hope this helps

It did. Thanks.

---

<div class="post-metadata">

**Author:** ![asherwood](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c67d28/32.png) [@asherwood](https://www.ruby-forum.com/u/asherwood)\
**Post date:** [October 28, 2008, 9:32pm UTC](https://www.ruby-forum.com/t/proper-way-to-define-a-subclass-within-parent-file/151990/4 "2008-10-28T21:32:16Z")

</div>

Scott Strattner wrote:

> > Another possibility, if the values in the instance variables shouldn’t  
> > change  
> > is to use constants:
> 
> I originally had methods to modify these class variables, but I just  
> tried using constants, and that worked. So I will probably create a  
> subclass for every kind of VLAN encountered (which will then define the  
> constant values for that particular subclass).

Note: when referring to constant Foo, use self.class::Foo in a subclass  
if you want dynamic lookup, otherwise Foo will statically be resolved to  
the one in the parent.

class Bar  
Foo = 1  
def test1  
Foo # always refers to Bar::Foo, even in a subclass  
end  
def test2  
self.class::Foo  
end  
end

class Baz \< Bar  
Foo = 2  
end

p Bar.new.test1 # prints 1  
p Baz.new.test1 # prints 1  
p Bar.new.test2 # prints 1  
p Baz.new.test2 # prints 2
