def Class
def method
self.type.send :new
[or perhaps tidier, "self.class.new"]
end
end
...
will result in this behavior
sub = SubClass.new
sub.method.type >> SubClass
...
A recent example of why this might be a good design pattern is that
subclasses of Array must re-write all the 'usefull' methods like select, etc.
to return the SubClass'd type since these methods return an Array.
This was actually discussed about a week ago, specifically taking the
example of class 'S' derived from 'String', where the inherited '+' method
in S returns a String not an S.
I can hear the arguments against :
"what if the subclassed methods do something perverse with the methods"
"what if the subclassed methods simply will not work if that is done"
etc.
I would say
Sub-classing should always be reserved to _extend_ objects, old behavior
should always remain - but may be added to.
Another objection centres around the arity and semantics of constructors.
Your code above assumes that all derived classes will have a constructor
which allows zero arguments. But this may not be true.
For a start, there are objects for which zero arguments are not meaningful:
irb(main):001:0> Regexp.new
ArgumentError: wrong # of argument
from (irb):1:in `initialize'
from (irb):1:in `new'
from (irb):1
That's not really a problem because in that case your code would say
self.type.send :new (arg)
However, say that a base class has a constructor which accepts 1 argument.
It does not necessarily follow that all derived classes will have a
constructor which accepts 1 argument: a derived class may well have other
instance variables which need initialising, and it may only make sense to
have a constructor which takes (say) 2 arguments.
In that case, self.type.send :new (arg)
will fail, even though it is fine in the base class.
You could _require_ that all derived classes implement a constructor with
the same arity as their parent class even if it would not normally make
sense to have one, perhaps taking defaults of 'nil' for the extra arguments
it needs. In that case it would be a kind of type coercion operator: "give
me an object of type SubClass, even though the parameters I am going to give
you are only sufficient to create an object of BaseClass".
You can't just create an instance of the base class using the base class's
constructor and just 'flip' the type to be SubClass; that would leave the
subclass's extra instance variables uninitialised, potentially giving you an
invalid object instance.
Oh, and remember that inheritance can have multiple levels. So given
Base new(arg1)
Sub1 < Base new(arg1,arg2)
Sub2 < Sub1 new(arg1,arg2,arg3)
then Sub2 would have to implement constructors of all three variants, just
so that it could use inherited methods from Base and Sub1 which construct
new objects of type "self.class"
This is all pretty nasty, because you can't write a working implementation
of Sub2 without knowing about all the different ancestor classes.
It would get even nastier if the subclass constructor has the same arity but
different semantics (e.g. Base.new takes a string but Subclass.new takes a
Regexp; or Subclass.new takes a string but does something different with it)
So, perhaps it would be cleaner to explicitly create an object of the base
class and then ask the subclass to "convert" it, which might involve filling
in its extra instance values with appropriate values or defaults.
class Base
def method
# instead of self.class.new call:
self.class.create_from_Base(Base.new)
end
def create_from_Base(a)
a
end
end
Base.create_from_Base is a virtual method, to be overridden in subclasses.
Effectively you have a new type of constructor: "construct given an instance
of a parent class", rather than "construct given some parameters".
You need a mechanism to perform the chaining required with multiple levels
of inheritance: for example, if 'a' is an object of class Sub2, then calling
'a.method' will call Sub2.create_from_Base, but this in turn needs to call
Sub1.create_from_Base followed by Sub2.create_from_Sub1.
I guess this could be done, by walking self.class.superclass up towards
Object. Sounds like quite a lot of scaffolding to run every time you create
an object instance though.
Regards,
Brian.
···
On Sat, Nov 09, 2002 at 12:52:24AM +0900, ahoward wrote: