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