0

When the ancestors of a module are displayed, for example with String:

String, Comparable, Object, Kernel, BasicObject

some of them (String, Object, BasicObject) are classes and others are not. Is there a notation to distinguish them? A possible candidate that came to mind was to use << instead of < for module inclusion:

String << Comparable < Object << Kernel < BasicObject

or conversely for class inheritance:

String < Comparable << Object < Kernel << BasicObject

but I am not sure. If there is no notation already out there, what do you think about the above? How is this expressed in UML?

sawa
  • 165,429
  • 45
  • 277
  • 381

1 Answers1

2

There is no such notation that I know of.

For the most part, though, I don't think one is necessary. In general (there are likely caveats here, but I can't think of any right now), once a module is part of the ancestor chain, it behaves just like a class in the ancestor chain. To use your String example, ''.is_a? Comparable returns true and you calling super in a method within String that Comparable defines will call Comparable's implementation.

The only difference is with regard to initialize, since you can't create an instance of a Module.

As for UML, given this, it can just be a normal ancestor just like a class (I think), as I don't believe UML has any way different way of representing modules.

Personally, I think your proposed notation is a bit hard to parse, and when I do care would rather just see it all spelled out:

a = String.ancestors
a.map{ |c| c.class.to_s.downcase }.zip(a).map { |o| o.join(' ') }.join(' < ')
#=> "class String < module Comparable < class Object < module PP::ObjectMixin < module Kernel < class BasicObject"
Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • 3
    In fact, it doesn't just behave *like* a class, it *is* a class. When you call `include`, Ruby creates a new class whose superclass is the superclass of the class the module is mixed into and whose method table pointer and constant table pointer point to the method table and constant table of the module, and makes that class the new superclass of the class it is mixed into. This class is called an *include class* and it is a *ghost class* similar to a *singleton class* (i.e. it is skipped, when you call `superclass`). – Jörg W Mittag Oct 15 '12 at 01:54
  • @JörgWMittag Interesting, did not know that. Perhaps tomorrow I'll dive into the C code for `include` for some exploratory fun. – Andrew Marshall Oct 15 '12 at 01:55
  • Do yourself a favor and try either the Ruby code for `include` in Rubinius or the English code in the Ruby Language Specification. – Jörg W Mittag Oct 15 '12 at 01:56
  • 1
    By the way: that's why adding methods to a module after it has been included works (because the method table isn't copied, just aliased) but including a module into a module doesn't (because the *include classes* are only created once, when calling `include`). – Jörg W Mittag Oct 15 '12 at 02:00