subclassing fundamental classes

D

Dan Zwell

xyz said:
Let's say I have a user-defined class as follows:

class C1
#-------------------------
def initialize(i, j)
@iv1 = Array.new(i, j)
end
#-------------------------
def append(i)
@iv1 << i
return(self)
end
#-------------------------
def append2X(i)
@iv1 << 2 * i
return(self)
end
#-------------------------
end

Now I subclass C1 to make C2:

class C2 < C1
#-------------------------
def initialize(inA)
@iv1 = inA
end
#-------------------------
def append(i)
@iv1 << i << i
return(self)
end
#-------------------------
def doubleLast()
@iv1[-1] *= 2
return(self)
end
#-------------------------
end

The internal state of the superclass (C1) is visible to methods in the subclass
(C2) and has a known name that can be used in the subclass (@iv1). Now let's
look at a similar situation but where the superclass is one of the "fundamental"
classes pre-packaged with Ruby (i.e. Array, Hash, String, etc.). A "fundamental"
class is one that is not constructed from some other Ruby class using Ruby
source but is instead constructed from the same underlying machinery as the
interpreter itself (in the current implementation this means C source). In the
following "???" denotes a name for an instance variable in the superclass.

class C3 < Array
def initialize(inArray)
??? = inArray
end
def append(i)
??? << i << i
return(self)
end
def join(i)
out = ""
sep = "#" * i
???.each { |e| out << sep + e.to_s + sep }
return(out)
end
end

What do I use in place of the ???'s above? That is, what name do I use in the
subclass (C3) for the instance state of a fundamental superclass (Array)?

When a superclass is fundamental, can I access instance state in said superclass
without having to resort to the underlying C interface?

In my specific case, I am using instances of Array to hold data in a particular
format (the array elements are Hash's whose keys are String's of a particular
format and whose values are Hash's of a particular format). I want to subclass
Array, add a couple of methods, override a couple of methods, and also use the
non-overridden methods of Array.

It looks like I could make this work by simply adding my new methods directly to
Array and using alternate (if less descriptive) names for the Array methods I
was planning on overriding (this would allow me to access the internal state of
Array using self). However this approach will make the code slightly less
readable since some Array variables will be generic Array's and some will be my
special version. And to make things worse, I actually have two special versions
of Array and was planning on constructing two separate subclasses.

Thanx.

Jake

I think it's just "self", but you'll have one problem because you can't
assign a value to self. I would try:

def initialize(inArray)
inArray.each {|elem| self << elem}
end

Dan
 
X

xyz

Let's say I have a user-defined class as follows:

class C1
#-------------------------
def initialize(i, j)
@iv1 = Array.new(i, j)
end
#-------------------------
def append(i)
@iv1 << i
return(self)
end
#-------------------------
def append2X(i)
@iv1 << 2 * i
return(self)
end
#-------------------------
end

Now I subclass C1 to make C2:

class C2 < C1
#-------------------------
def initialize(inA)
@iv1 = inA
end
#-------------------------
def append(i)
@iv1 << i << i
return(self)
end
#-------------------------
def doubleLast()
@iv1[-1] *= 2
return(self)
end
#-------------------------
end

The internal state of the superclass (C1) is visible to methods in the subclass
(C2) and has a known name that can be used in the subclass (@iv1). Now let's
look at a similar situation but where the superclass is one of the "fundamental"
classes pre-packaged with Ruby (i.e. Array, Hash, String, etc.). A "fundamental"
class is one that is not constructed from some other Ruby class using Ruby
source but is instead constructed from the same underlying machinery as the
interpreter itself (in the current implementation this means C source). In the
following "???" denotes a name for an instance variable in the superclass.

class C3 < Array
def initialize(inArray)
??? = inArray
end
def append(i)
??? << i << i
return(self)
end
def join(i)
out = ""
sep = "#" * i
???.each { |e| out << sep + e.to_s + sep }
return(out)
end
end

What do I use in place of the ???'s above? That is, what name do I use in the
subclass (C3) for the instance state of a fundamental superclass (Array)?

When a superclass is fundamental, can I access instance state in said superclass
without having to resort to the underlying C interface?

In my specific case, I am using instances of Array to hold data in a particular
format (the array elements are Hash's whose keys are String's of a particular
format and whose values are Hash's of a particular format). I want to subclass
Array, add a couple of methods, override a couple of methods, and also use the
non-overridden methods of Array.

It looks like I could make this work by simply adding my new methods directly to
Array and using alternate (if less descriptive) names for the Array methods I
was planning on overriding (this would allow me to access the internal state of
Array using self). However this approach will make the code slightly less
readable since some Array variables will be generic Array's and some will be my
special version. And to make things worse, I actually have two special versions
of Array and was planning on constructing two separate subclasses.

Thanx.

Jake
 
B

Brian Candler

class C3 < Array
def initialize(inArray)
??? = inArray
end
def append(i)
??? << i << i
return(self)
end
def join(i)
out = ""
sep = "#" * i
???.each { |e| out << sep + e.to_s + sep }
return(out)
end
end

What do I use in place of the ???'s above? That is, what name do I use in the
subclass (C3) for the instance state of a fundamental superclass (Array)?

self. An Array doesn't store its array in an instance variable; the object
*is* the array.

You can add instance variables in your subclass though.

You may find Array#replace useful, if you want to replace your array
contents with another array. (So 'self' still points to the same object of
course, but the array contents are different). This is almost the same as
having the array in @iv and then changing @iv to point to another array. The
difference is that if you had @iv, you could point it to some other object
which *isn't* an array.
In my specific case, I am using instances of Array to hold data in a particular
format (the array elements are Hash's whose keys are String's of a particular
format and whose values are Hash's of a particular format). I want to subclass
Array, add a couple of methods, override a couple of methods, and also use the
non-overridden methods of Array.

Consider delegation instead of subclassing. In the long run it gives you
more flexibility.

Subclassing is the evil you learn from Object Oriented Programming courses.
It's taught so thoroughly that you come to believe that subclassing *is*
OOP. In fact, once you ditch subclassing, and worrying whether a Square is a
Rectangle or vice versa, life becomes much more straightforward :)

Regards,

Brian.
 
R

Robert Klemme

In my specific case, I am using instances of Array to hold data in a particular
format (the array elements are Hash's whose keys are String's of a particular
format and whose values are Hash's of a particular format). I want to subclass
Array, add a couple of methods, override a couple of methods, and also use the
non-overridden methods of Array.

Please note that more often than not it is not a good idea to do this
(creating sub classes of core classes). Reason: you typically want some
specific operations on the content but if your class *is an* Array you
get all the Array manipulation methods unless you undefine or override
them. It's typically simpler and cleaner to just make your class *have
an* Array and only provide the interface to the public that you want to
allow.

Kind regards

robert
 
X

xyz

Array.replace works (at least for my reasonably accurate test code).

i always wondered why Array, Hash, etc. had replace (which seemed superfluous
given that i can just do an assign). now i know at least one good reason why -
they effectively give one a channel to write the instance data of fundamental
classes.

and technically (speaking C here since that's what's currently under the hood),
self isn't the physical array, it's a pointer to an object struct containing an
RBasic struct, a pointer to an instance variable array (one of whose pointers
points to an RArray struct which contains the address of the physical array
storage and the length), and a pointer to the class struct, etc.

thanx again for the pointer :) to replace.

jake
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top