# Creating sub-classes using Struct

**URL:** <https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552>\
**Category:** Ruby\
**Created:** [May 6, 2006, 5:18pm UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552 "2006-05-06T17:18:55Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![eliben](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3bc359/32.png) [@eliben](https://www.ruby-forum.com/u/eliben)\
**Post date:** [May 6, 2006, 5:18pm UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552/1 "2006-05-06T17:18:55Z")

</div>

Hello,

There are two Ruby features I want to combine. One is sub-classes (or  
embedded classes):

class Foo  
def initialize(x)  
puts “new Foo #{x}”  
end

```
class Bar
	def initialize(y)
		puts "new Bar #{y}"
	end
end

```

end

joe = Foo::Bar.new(12) # prints “new Bar 12”

Another is dynamic creation of new classes using Struct:

Customer = Struct.new(:name, :address) #=\> Customer  
eddy = Customer.new(“Dave”, “123 Main”)

Here ‘Customer’ is a class and ‘eddy’ is an instance of the Customer  
class.

Now, by combining the features, I mean creating a subclass of Foo  
dynamically, using Struct. The following pseudo-code demonstates it  
(pseudo because it obviously doesn’t work and only shows what I’m trying  
to do):

class Foo  
def initialize(x)  
puts “new Foo #{x}”  
end

```
Bar = Struct.new(:name, :address)

```

end

eddy = Foo::Bar.new(“Dave”, “123 Main”)

How can this be done ?

TIA  
Eli

---

<div class="post-metadata">

**Author:** ![eliben](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3bc359/32.png) [@eliben](https://www.ruby-forum.com/u/eliben)\
**Post date:** [May 6, 2006, 7:56pm UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552/2 "2006-05-06T19:56:32Z")

</div>

2006/5/6, Eli B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> ```
> class Bar
> 
> ```
> 
> Another is dynamic creation of new classes using Struct:  
> to do):
> 
> How can this be done ?

You’ll have to modify Struct to be able to create sub classes of  
arbitrary classes and not just Object. Btw, if feels a bit strange to  
have a nested class that is a sub class of the outer class. By that  
twist it contains itself - I think this is not a good idea.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![eliben](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3bc359/32.png) [@eliben](https://www.ruby-forum.com/u/eliben)\
**Post date:** [May 6, 2006, 8:09pm UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552/3 "2006-05-06T20:09:11Z")

</div>

On May 6, 2006, at 11:19 AM, Eli B. wrote:

> class Bar  
> Another is dynamic creation of new classes using Struct:  
> trying  
> eddy = Foo::Bar.new(“Dave”, “123 Main”)
> 
> How can this be done ?

I’m confused. This works for me, the above code works fine for me.

Putting a class inside another class does not subclass it though (Nor  
is it supposed to, you’re just setting a constant for the enclosing  
class).

---

<div class="post-metadata">

**Author:** ![eliben](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3bc359/32.png) [@eliben](https://www.ruby-forum.com/u/eliben)\
**Post date:** [May 6, 2006, 8:55pm UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552/4 "2006-05-06T20:55:52Z")

</div>

Robert K. wrote:

> 2006/5/6, Eli B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
> 
> > ```
> > class Bar
> > 
> > ```
> > 
> > Another is dynamic creation of new classes using Struct:  
> > to do):
> > 
> > How can this be done ?
> 
> You’ll have to modify Struct to be able to create sub classes of  
> arbitrary classes and not just Object. Btw, if feels a bit strange to  
> have a nested class that is a sub class of the outer class. By that  
> twist it contains itself - I think this is not a good idea.

Sorry, I don’t understand what you mean by “have a nested class that is  
a sub class of the outer class”.

Perhaps it’s better for me to explain the motivation for what I’m trying  
to do. Simplifying:

I have a flat-file full of records. The way records are stored can be  
customized via a separate configuration file. I want to have a class  
Database which is a container of Record classes. The Record is best  
implemented as a Struct, IMHO, and I want to create the class  
dynamically after reading the configuration (which says which fields  
there are in a Record). I think it would be convenient for a Record to  
be a subclass of Database, since there is no point having Records  
without a Database.

---

<div class="post-metadata">

**Author:** ![eliben](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3bc359/32.png) [@eliben](https://www.ruby-forum.com/u/eliben)\
**Post date:** [May 6, 2006, 9:31pm UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552/5 "2006-05-06T21:31:43Z")

</div>

On 5/6/06, Eli B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I have a flat-file full of records. The way records are stored can be  
> customized via a separate configuration file. I want to have a class  
> Database which is a container of Record classes. The Record is best  
> implemented as a Struct, IMHO, and I want to create the class  
> dynamically after reading the configuration (which says which fields  
> there are in a Record). I think it would be convenient for a Record to  
> be a subclass of Database, since there is no point having Records  
> without a Database.

I think that what you mean by “subclass” is something different than  
the traditional meaning of the term.

Subclassing establishes a “is a” relation between the two classes. To  
do it in Ruby you’d write:

class Database  
#code goes here  
end

class Record \< Database  
#more code goes here  
end

I don’t think this is completely correct, however, since a Record is  
not a Database. The relationship you want to establish is “contains”:  
a Database contains Records. To do this, you’d have to declare a  
collection of Records as an attribute of Database, doing something  
like this:

class Database  
def initialize()  
@records = []  
end

def add\_record(record)  
@records \<\< record  
end

#et cetera

end

Defining Record within Database, as in your first example, doesn’t  
necessarily do any of those things, and is more commonly known as  
creating a “nested class”.

If you want to define Record dinamically, you could maybe do something  
like this:

class Record  
def initialize(\*attribs)  
@internal\_class = Struct.new(\*attribs)  
@internal\_object = @internal\_class.new  
end

def method\_missing(name, \*args)  
if @internal\_object.respond\_to? name  
@internal\_object.send(name, \*args)  
else super(name, \*args)  
end  
end

def inspect  
@internal\_object.inspect  
end

end

This way, everytime you create a new Record object, you’ll need to  
define what attributes it has (and these attributes would probably  
come from you configuration files). You can place the code for the  
Record class inside the Database class to make it a nested class, and  
you can create an attribute for Database that is an Array or Hash of  
Records.

---

<div class="post-metadata">

**Author:** ![eliben](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3bc359/32.png) [@eliben](https://www.ruby-forum.com/u/eliben)\
**Post date:** [May 6, 2006, 9:43pm UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552/6 "2006-05-06T21:43:57Z")

</div>

On May 6, 2006, at 2:55 PM, Eli B. wrote:

> > arbitrary classes and not just Object. Btw, if feels a bit strange to  
> > to do. Simplifying:
> 
> I have a flat-file full of records. The way records are stored can be  
> customized via a separate configuration file. I want to have a class  
> Database which is a container of Record classes. The Record is best  
> implemented as a Struct, IMHO, and I want to create the class  
> dynamically after reading the configuration (which says which fields  
> there are in a Record). I think it would be convenient for a Record to  
> be a subclass of Database, since there is no point having Records  
> without a Database.

Eh, I’m not sure you get the is-a relationship. Saying that a Record  
is a subclass of Database implies that anywhere you would use a  
Database you could use a Record instead. That doesn’t really make  
sense. It would also seem to imply that a Record could contain many  
records. Instead of

class Database  
…  
end

class Record \< Database  
…  
end

I would suggest

class Database  
def self.new(file\_containing\_info)  
fields = parse\_field\_format(file\_containing\_info)  
Database.const\_set('Record", Struct.new(\*fields))  
super  
end

def initialize(file)  
@records = []  
read\_each\_record\_in\_file(file) do |record\_data|  
record = Database::Record.new  
extract\_record\_data\_into(record\_data, record)  
@records \<\< record  
end  
end  
end

---

<div class="post-metadata">

**Author:** ![eliben](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3bc359/32.png) [@eliben](https://www.ruby-forum.com/u/eliben)\
**Post date:** [May 6, 2006, 10:21pm UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552/7 "2006-05-06T22:21:02Z")

</div>

Logan C. wrote:

> On May 6, 2006, at 2:55 PM, Eli B. wrote:
> 
> > > arbitrary classes and not just Object. Btw, if feels a bit strange to  
> > > to do. Simplifying:
> > 
> > I have a flat-file full of records. The way records are stored can be  
> > customized via a separate configuration file. I want to have a class  
> > Database which is a container of Record classes. The Record is best  
> > implemented as a Struct, IMHO, and I want to create the class  
> > dynamically after reading the configuration (which says which fields  
> > there are in a Record). I think it would be convenient for a Record to  
> > be a subclass of Database, since there is no point having Records  
> > without a Database.
> 
> Eh, I’m not sure you get the is-a relationship. Saying that a Record  
> is a subclass of Database implies that anywhere you would use a  
> Database you could use a Record instead. That doesn’t really make  
> sense. It would also seem to imply that a Record could contain many  
> records. Instead of
> 
> class Database  
> …  
> end
> 
> class Record \< Database  
> …  
> end

It seems that I managed to completely confuse everyone using an  
inaccurate description. By sub-class I meant a nested class here, not a  
child in is-a inheritence. I don’t know what I was thinking 🙂

> I would suggest
> 
> class Database  
> def self.new(file\_containing\_info)  
> fields = parse\_field\_format(file\_containing\_info)  
> Database.const\_set('Record", Struct.new(\*fields))  
> super  
> end

Excellent ! const\_set is what I was missing to get my solution working.  
No more “dynamic constant assignment” errors for me 🙂

> def initialize(file)  
> @records = []  
> read\_each\_record\_in\_file(file) do |record\_data|  
> record = Database::Record.new  
> extract\_record\_data\_into(record\_data, record)  
> @records \<\< record  
> end  
> end  
> end

This looks like what I need. Many thanks

---

<div class="post-metadata">

**Author:** ![eliben](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/3bc359/32.png) [@eliben](https://www.ruby-forum.com/u/eliben)\
**Post date:** [May 7, 2006, 8:01am UTC](https://www.ruby-forum.com/t/creating-sub-classes-using-struct/94552/8 "2006-05-07T08:01:31Z")

</div>

Eli B. wrote:

> Excellent ! const\_set is what I was missing to get my solution working.  
> No more “dynamic constant assignment” errors for me 🙂

FWIW, you can look at Superstruct which I wrote awhile back.  
Disclaimer: I think it has bugs not caught by the unit tests.  
Also the code is probably not very pretty in places.

As I recall it’s at: [http://sstruct.rubyforge.org](http://sstruct.rubyforge.org)

Cheers,  
Hal
