Type/Class Unification in Ruby
Clemens Hintze
c.hintze at gmx.net
Wed Nov 17 03:13:36 EST 1999
Hi,
Greg, you have done a great analyze! I wish you would have done it
sooner ;-) It would have spare me some time to fiddle that out on my
own. This part of Ruby is, unfortunately, not too well documented. :-(
But in addition to your analyze, may I add some remarks?
>>>>> "Greg" == Greg Ewing <greg.ewing at compaq.com> writes:
[...]
Greg> 2) A class can only inherit from at most one other class.
This is, in fact, true. But it is worth mentioning, that Ruby features
single inheritance *by*purpose*. Not because of the implementation
details!
If it would implement multi-inheritance, the class structure could
e.g. use an array of pointer to all such C structs, not only one
pointer, as implemented now!
Greg> The only methods which actually create C structures are the
Greg> built-in instantiation methods of the built-in classes, so
Greg> even if you define your own instantiation method in your
Greg> subclass, it eventually has to call a built-in one somewhere
Greg> up its inheritance chain, which knows what kind of C
Greg> structure is needed.
That is not totally true (or, perhaps, I misunderstood you). You have
to differ two kind of class-building. you seem to describe, how Ruby's
built-in classes are implemented. But there is also a second way, that
should be used by own extensions. *Only* Ruby built-in (means built
into the interpreter) classes, should use the way you have described.
The second (preferred) way is, to build instances of class DATA
wrapping the C struct you have allocated for your extension. That DATA
instance is marked as beeing not a DATA instance, but an instance of
your extension class! So that means, that *you* would allocate your
instance!
Deriving a Ruby class coded in C from another one also coded in C,
seems to be the only right tricky part of that language, IMHO. :-)
Greg> This scheme will fail if you somehow manage to extract a
Greg> built-in method out of one class and stuff it into
Greg> another. However there doesn't seem to be any obvious way to
Greg> do this (nothing like myClass.__dict__["foo"] in Python). So
Greg> it seems to be safe.
Good derivation! I have also missed it for some time. But as Ruby
features closures, I had learned to use them instead of extraced
methods. Anyway Ruby has no functions, only methods.
You could extract a method object (means a method implementation). But
you would not be able to use it out-of-context of the class it was
taken from! As matz (the author of Ruby) has told me, methods are too
strong connected to the class they belongs to (performance reasons).
Greg> Now, what happens if you assign to a new instance variable
Greg> in a method of your subclass of a built-in class? At first
Greg> sight it seems that this can't possibly work, because the C
Greg> structs of built-in types don't have any place to store
Greg> arbitrary instance variables.
;-)))))))
Greg> When I tried it, however, to my surprise, it worked! It
Greg> turns out that there is a global table whose purpose is to
Greg> hold the values of these instance variables (in Python terms
Greg> it is a dictionary of dictionaries, indexed by
Greg> [object][variable_name]). Python might be able to use a
That was a great idea from matz, IMHO! :-)
Greg> similar solution, although it might cause ref counting
Greg> problems.
Once again, thanks for Ruby's true garbage collection! :-)
Greg> As a final note, some built-in classes, such as Fixnum,
Greg> don't have any instantiation method, so although you can
Greg> subclass them, there's no point because you can never create
Greg> an instance of your subclass.
In addition to your analyze: in the past, at least the classes of
Numeric and childs had instanstiation methods. But some user of Ruby
have convinced matz, that it would make no sense to derive another
numeric type from them. So the methods were delete. The big exception,
AFAIK, was class Fixnum. It never had any instanciation method, as it
doesn't wrap any struct. The pointer-to-struct is 'misused' as
contents of Fixnum. If I remember right, Smalltalk has also chosen
that way for implementing SmallInteger.
Greg> Others, however, such as Array (Ruby's version of ListType)
Greg> do have an instantiation method, and subclasses work just
Greg> the way you'd expect.
It is worth mentioning too, that it is often not necessary to derive
something from e.g. Array. Often it is better to use the module
mechanism to add methods to class Array or some of its instances
during runtime.
You can do that also in your extension. So if Ruby's Array would not have
'push' and 'pop' methods, I would not derive a class Stack from Array,
but I would implement a module Stack (implementing 'push' and 'pop')
and simply add them to class Array, whenever I need them ... :-)))
Greg> Hoping this has been enlightening, Greg
We would need more of such ... :-)
Clemens.
More information about the Python-list
mailing list