[Archive copy mirrored from the URL: http://www.geocities.com/WallStreet/Floor/5815/ooxmledi.htm; see this canonical version of the document.]

Ideas about Subclassing and Inheritance in Generic Documents

Paul Prescod


The concept of subclassing is an important one in modern object oriented software design, but the idea of "subclasses" and "superclasses" is fundamental to how we think about our world. These concepts are reinvented in DTD after DTD through parameter entities and deserve a direct expression that could be used throughout an SGML authoring and processing system.

There is a lesser notion, of inheritance, which has practical utility but is not as crucial. Inheritance allows one set of objects to get the properties of another set of object "for free". In SGML this would probably mean that one element would "inherit" the attribute declarations and content model of another element. SGML DTDs also use parameter entities to model inheritance. Inheritance is basically just a code saving device which allows different parts of the DTD to evolve independently.

The concept of inheritance is not as old or well established as that of subclassing and I do not think that it is as important in SGML. Inheritance is only a code saving device. Subclassing has implications that can allow us to build more interesting editors, processors and other tools. Code saving is important, but not as important as being allowed to express new kinds of type relationships naturally.

Programming language research has found that there are times when you want to subclass without inheriting and even inherit without subclassing. Early object oriented programming languages did not make a distinction. Modern programming languages give you some options in this regard. C++ allows "private" inheritance which is inheritance ("inheriting code") without subclassing (claiming to always be replaceable for elements of the parent class). Java's "interfaces" allows subclassing without inheritance. I believe that the problems that have led to this need for a separation are all related to multiple inheritance and are also applicable to markup languages. More on this later.

This essay will outline the ideas without making concrete proposals for extensions for SGML. The goal is to get people thinking and to expose the flaws in our current mechanisms, parameter entities and architectural forms.


A Straw Person Syntax


For our purposes, an element type is a subclass of another element type if it is substitutable where ever the first element is and declared to be a subclass. So if I have an animal element type, cat would be an appropriate subclass because any content model that needs an animal could be fulfilled with a cat. Here's an example of a syntax that would allow this:

<!ELEMENT animal ANY>
<!ATTLIST animal FOOD CDATA #REQUIRED
HABITAT NAME #REQUIRED>

<!ELEMENT cat TYPEOF (animal) (#PCDATA)>
<!ATTLIST cat FOOD NAME #REQUIRED
HABITAT NAME #REQUIRED>

Now there are a few important things buried in this syntax.


Subclassing


The first is that the subclass must implement the base class's interface faithfully. Since animal has ANY content model, cat can have ANY content model. But cat may also have a more restricted content model. In this case they do. Cats may only have text content. Animal allows food to be any string of SGML characters, but cat restricts the set to only the name characters. One important thing to note is that before a single document has been created, this DTD can be checked to guarantee complete conformance of element type subclasses to element type superclasses so that any element of type "cat" that is created is absolutely guaranteed to be also valid as an "animal". This means that cats are guaranteed to be substitutable for animals.

So this is now a valid document:

<!DOCTYPE ZOO[
<!ENTITY % animals SYSTEM
"http://www.animalsRUs.com/animal.dtd">
%animal;
<!ELEMENT ZOO (ANIMAL+)>
]>
<ZOO>
<CAT FOOD="Nibbles" HABITAT="Domestic">
<CAT FOOD="Rats" HABITAT="Barn">
<CAT FOOD="People" HABITAT="Jungle">
</ZOO>

It would be illegal for "cat" to extend "HABITAT" to type CDATA or NUMBER because there exist CDATA strings and NUMBERs that are not valid NAMEs. This is a little bit of an inversion from OOP, because in OOP a subclass must accept any "input" that a parent class can. We think of content models as "accepting input".

The reason for this inversion is that the content of an element is actually "output", not input. It is input by the human, but output
by the parser.

Think of each element as an object that implicitly has methods to retrieve each attribute and its content. For instance in Python I might make a rule for animals that absolutely depended on HABITAT being a name, and not random CDATA:

def ANIMAL( FOOD, HABITAT ):
print "I eat", Cdata2String( FOOD )
print "I live in", Name2String( HABITAT )

Now you can see why it is so important that cat not be more "flexible" about the properties it has in common with animal. This would be even more vital if the property were declared to be a number and I were going to use the language's built-in coercion tools to convert the string representation of the number to an integer. More generally, an important reason that SGML has DTDs is so that software can depend on documents conforming to them. We cannot weaken those guarantees in moving adding inheritance and subclassing to SGML.

On the other hand, cat could create new attributes that would be totally ignored when it was being treated as an animal. Generally speaking, attributes seem more intrinsically amenable to concepts of subclassing than content, because they are "random access" in some sense, as are methods in OOP. Perhaps in adding OO features to SGML we will also choose to make attributes more powerful (for instance by allowing them to have content models and explicit substructure like elements).

Substitutability also works in the DTD. That means that a subclass of ZOO could have a content model that was restricted to subclasses of ANIMAL:

<!DOCTYPE FLEA-CIRCUS[
<!ENTITY % zoo SYSTEM "
http://www.zoosRUs.com/zoo.dtd">
%zoo;
<!ELEMENT FLEA TYPEOF ANIMAL>
<!ELEMENT FLEA-CIRCUS TYPEOF ZOO (FLEA+)>
]>

The flea-circus element type is a special subclass of zoo that can only accept fleas.

We say that each element type listed in a content model has a "role". When you create an SGML document, each element in the document "matches up" against some element in the DTD unambiguously. I say that it fulfills that "role". Content models in subclasses are also "matched" against content models in their superclasses. Matching element types must be subclasses of the element type that they match in in the superclass, just as "FLEA" in "FLEA-CIRCUS" is a subclass of "ANIMAL" in "ZOO".


Inheritance


Note also that the subclass in my proposal does not inherit anything. It re-declares a content model and an attribute list. I do not have any particular problem with a system in which things which are not redeclared in subclasses are presumed to be inherited from superclasses unchanged. But it is important to me that we understand that inheritance and subclassing are two different things and one can occur without the other. From here on in this essay, I *will* pretend that an inheritance rule has been designed. If an element declaration does not have a content model, it means that the content model is inherited. If it does not repeat a particular one of its superclasses' attributes, it means that the attribute has been inherited. This is just a convenience measure and does not change the basic concept of subclassing. Still convenience is important. Without inheritance, changes to the base classes must be manually propagated down to subclasses. In practice, this makes maintenance more difficult.


Multiple Inheritance/Subclassing


There is an interesting inversion in the document OO model vs. OOP. In OOP, multiple subclassing is widely understood to be useful, but multiple inheritance is highly controversial because of confusion that can be caused repeated inheritance and the repeated instance variables that repeated inheritance causes. In documents, the problem seems to be the opposite. Multiple subclassing is dangerous as inheritance is in OOP, because it may be ambiguous what role a subclassed element plays in a superclass's content model:

<!ELEMENT FOO (IMAGE|LINK|P)+>
<!ELEMENT CLICKABLE-LINK TYPEOF (IMAGE,LINK)>

<FOO><CLICKABLE-LINK><CLICKABLE-LINK></FOO>

The "archform" solution to this problem is to require an attribute to specify what base class each element should be converted to, and thus what role it plays. I think that this requires authors to have too much knowledge of base classes.

Another solution would be merely to outlaw multiple subclassing which introduces ambiguity. This may be too restrictive in some cases. A third solution might describe some form of "subclassing in context." This last solution is inspired by architectural forms and their use with SGML's Link feature to describe a particular SGML element as a subclass of one element when it appears in one context and of another in another context.

These options must be thought through some more and tested with real DTDs. Multiple subclassing may turn out to be a point of weakness or confusion in our system just as multiple inheritance is in OOP.


Motivation


You might be wondering: "is all of this just angels on the head of a pin?" Am I just trying to align SGML with OOP just for the sake of doing so? No not all. Real world SGML documents emulate subclassing and inheritance with parameter entities all of the time.

Let me use as evidence the world's most popular DTD, HTML. The version I will use for my demonstration is HTML 3.2.


Subclassing


HTML has a heading class defined like this:

<!ENTITY % heading "H1|H2|H3|H4|H5|H6">
<!ELEMENT ( %heading )  - -  (%text;)*>
<!ATTLIST ( %heading )
        align  (left|center|right) #IMPLIED>

As you can see, headings have absolutely the same content model and attributes no matter where they occur. So their properties of completely inheritable. It turns out that one heading is always usable anywhere another is. They are *always* completely interchangeable in content models. This would be modeled in a true subclassing/inheritance system like this:

<!CLASS heading (text)*>
<!ATTLIST heading align  (left|center|right) #IMPLIED>
<!ELEMENT (H1|H2|H3|H4|H5|H6) TYPEOF heading>

Each of the individual types of headings would inherit the attributes and content model from the parent. Headings would also be completely interchangeable as they are now. The declaration for heading uses a "CLASS" keyword instead of an "ELEMENT" declaration because headings cannot be inserted in documents themselves. You must choose some subclass of heading to insert (H1 through H6).

There are a few major benefits here over parameter entities.

(element heading
    (make paragraph
font-size: (- 20 (HEADING-LEVEL (gi (current-node))))))

This code would be triggered on any occurrence of a heading element, including subclasses of heading. It would check the numeric suffix of the heading and choose an appropriate font size. The code continues to work with heading extensions as long as they continue the naming pattern (e.g. H7 and H8). If you didn't want to depend on this convention, you could treat other subclasses as H6.

The equivalent DSSSL code for SGML as we know it would require a construction rule for each heading and there would be no easy way to handle new subclasses.


Inheritance


Now here's a case from the same DTD where you want inheritance, but not subclassing. There are many objects in HTML that have href attributes that point to resources. Examples include A, AREA, LINK, BASE and so forth. We might want to define this attribute in one place and reuse it. OO programmers call this a "mixin". We also might not to. DTD authors should be careful. It is easy to abuse inheritance and inheriting one attribute at a time from various places can make DTDs hard to read, just as overuse of parameter entities can. Nevertheless, it may be useful to do this to centralize the definition of HREF. I will also demonstrate inheritance from a "shape" base class. Shape is a mixin that introduces "width" and "height" attributes.

<!ELEMENT has-href ANY>
<!ATTLIST has-href href CDATA #IMPLIED>

<!ELEMENT sizeable ANY>
<!ATTLIST sizeable height NUMBER #IMPLIED
   width NUMBER #IMPLIED>

<!ELEMENT area INHERITS (sizeable, has-href) EMPTY>

Now area inherits both sets of attributes. This means that a change to one of those base classes propagates down to the children classes. Of course if you make a change to the base that is incompatible with your documents, they will break, just as with parameter entities or classes in an OO language. On the other hand, the benefit of inheritance without subclassing is that you can always unhook area from one or both of its base classes without anything breaking. Inheritance relationships aren't reflected in content models of other elements or in the document itself. They are just a maintenance facility for DTD designers. Still, the direct encoding of inheritance hierarchies in DTDs would present interesting opportunities for graphical SGML DTD editing tools. Right now they emulate inheritance hierarchies with parameter entities. Inheritance hierarchy information is thus lost in the transmission from one such program to another. This would not be the case if SGML had a first-class inheritance feature.


A Word About Architectural Forms


Architectural forms were invented in the 10 years between SGML's creation and the time it was allowed to be revised. In the author's opinion, they reflect those limitations. Archforms allow subclassing at the application level, but do not convey any subclass information to the parser itself.

Now SGML is up for revision, not just correction, but revision. In XML, we should take advantage of that fact and do the job right. We have a great opportunity here that was not available when archforms were invented.


Architectural Forms - Subclassing


Architectural forms do not directly express the notion that element type A ISA subclass of element type B at the SGML parser level.

Since archforms do not have parser level subclassing, the parser cannot check subclasses for conformance as OO language parsers do. Nor can DTDs be checked for conformance to meta-DTDs.

More subtly, I don't think the true subclassing relationship finds any direct expression in the archform concept at all. Rather archforms allow you to express that individual elements of type A ARE-ALSO-OF type B. If every single element of type A conforms to this relationship, then you could *conclude* that element type A ISA subclass of element type B, but there is no direct relationship. This has some interesting implications: first there is no sense in which an "architectural DTD" is a "meta-DTD". It was never a DTD for DTDs (which is, I think, the most obvious meaning for meta-DTD), but it is not even a "DTD superclass" or "DTD base class" or anything similar. There need not be any relationship between element types in the DTDs at all and if there is, the relationship is by convention, not language features.

To put this in terms of the model above, every element type in a derived "by default" subclasses from *every* element type in the base DTD. You must restrict the subclassing of a particular element by setting an attribute. You may restrict the subclassing of all of an element type by using a fixed attribute.

Another problem is that there is absolutely no way to express that an element within the same DTD conforms to the interface (content model and attributes) defined by another element in the same DTD and is a valid replacement for that element. There are tricks that you can use with parameter entities to subclass from another DTD in the same physical file. You can even share may elements. But if we define a DTD to be a set of declarations, then you *cannot* directly inherit from an element type in the same logical DTD.


Architectural Forms - Inheritance


Architectural forms do not allow any inheritance of element type "properties" at all. You cannot inherit attribute values or content models at the parser level. Even at the application level, the accuracy of calling what goes on in Architectural Forms "inheritance" is dubious. Rather it seems more like delegation, as in Microsoft's COM model. A particular element can support many "interfaces" and using attributes you can "delegate" between them so that a method (attribute) that is called one thing in one interface (architectural form) is called another thing in another.


Architectural Forms- Safety


Architectural form "subclasses" (element types with fixed attributes) are not constrained by the architectural form mechanism to be strict element type subclasses. This means that in some cases an inappropriate or merely insufficiently strict mapping will allow an author to make a document which conforms to its DTD, but not to some architectural DTD. Disturbingly, there is almost nothing that, for instance, an SGML editor can do to meaningfully report this error. When I say "meaningfully report", I mean report in the terms of the DTD that the author is familiar with. After all, the error is not caught in this DTD and thus is not expressible in those terms. Instead you will get an error message like "XML-LINK not allowed at this point in content of RDF-AUTHOR-INFO element in RDF-SPEC meta-DTD" when the author's actual mistake was putting  an element named "WebLink" in an element named "BiblioInfo" before an element named "AuthorInfo" instead of after it in a DTD called "THESIS-MARKUP-LANGUAGE".

Proponents of architectural forms will argue that allowing non-strict subclassing allows flexibility that DTD designers need for mapping one DTD to another. This is a good point. One of Architectural forms great strengths is that they provide a (relatively) simple syntax for expressing mappings from documents conforming to one DTD to documents conforming to another. This is absolutely vital to maintain the balance between generic markup's extensibility and the need to standardize on particular DTDs expected by software. This role cannot be completely filled by constrained inheritance. Element types must be *designed* to be subclasses of other element types. But architectural mapping can be done even for documents that just "happen" to always conform.

My argument in response is that XML already has a transformation language. XSL can be used to transform from generic XML to HTML. It would be a tiny extension to allow it to be used for generic XML -> XML transformations. If we then take a declarative, no-lookahead subset, we will have something that can be implemented right in the parser to build a grove conforming to a different DTD. It would also be more powerful than architectural forms. Though archforms mappings can theoretically be set up after both DTDs have been designed, my experience is that this rarely works in practice unless the superclass DTD is very flexible and non-prescriptive, because archforms are not a full transformation language and have very little power to move things around.

So in a practical sense, I think that a standardized, simple transformation language is still needed and that subclassing will suffice for most of the cases where archforms work now.

 


Architectural Forms - Syntax


I feel that attributes are a confusing place to put type information. People (rightly, IMO) expect element type information to be explicit in the DTD and invisible in the instance. I also think that people rightly expect the language to support specific keywords that provide inheritance, and not have inheritance "implied" through special "magical" attributes. Attributes made sense for archforms because SGML could not be changed. But times have changed.

I believe that we need keywords and a parser-level understanding of subclassing semantics.

Paul Prescod


Author's Note:

This is something I wrote in response to clarify my own ideas about inheritance, subclassing, architectural forms and SGML documents. I hope it is useful to others and will make it into a web page if it seems useful to do so. Please ignore typos. Conversation on the document should be in XML-DEV (or in private email) since inheritance is not on the XML WG's immediate agenda (AFAIK).

Thanks to Steven Newcomb and Peter Newcomb for their individual comments on some of the ideas. This does *not* represent an expression of consensus however. :)


Comments from Martin Bryan


Paul,

I really like your inheritance paper, but would like to suggest a minor change.

Firstly let me pick up on the name question. Because of the preconceived ideas that programmers have about what inheritance and subclassing involves I would love to get away from these terms.  I really liked the term Environmental Acquisition
defined in

> http://www.cs.technion.ac.il/~david/Papers/Tech_Reports/lpcr9507.PS.gz
>in:
> http://www.cs.technion.ac.il/~david/publications.html
>
This fits in beautifully with SGML as it incorporates the concept of being able to use context to determine the meaning of elements, which is one of the great plusses of SGML. This fits in nicely with what has been done in HyTime and DSSSL to allow querying of context within groves.

The one area of concern I have with your proposal is over the position of INHERITS. Unlike the other keywords you have proposed this defines the attributes to be associated with the following named parent rather than a mapping to be applied  to the following element name. I would like, therefore, to distinguish this fact by placing it after the model group rather than before it. e.g.

<!ELEMENT area  EMPTY INHERITS (sizeable, has-href)>

This would have the advantage that you could then combine TYPEOF and inherits:

<!ELEMENT dog TYPEOF animal (puppies+) INHERITS (pedigree, kept-by)>

> Architectural forms do not directly express the notion that element type A ISA subclass of element type B at the SGML parser level.

Not at parser level, but at architectural processor level, where the architectural processor could be a spawned SGML parser working from the meta-DTD. That's deliberate.

> Since archforms do not have parser level subclassing, the parser cannot check subclasses for conformance as OO language parsers do. Nor can DTDs be checked for conformance to meta-DTDs.

Again why presume it has to be done by a single parser? There may be good reasons for keeping these separate.

>More subtly, I don't think the true subclassing relationship finds any direct expression in the archform concept at all. Rather archforms allow you to express that individual elements of type A ARE-ALSO-OF type B.

This is the key - architectural forms are not subclasses, they are ways of identifying that processing relevant for a known class of objects are also relevant for this new class of object. They are about reusing existing knowledge/coding rather than about inheriting properties per se. This is the problem with using terms such as subclassing and inheritance to describe them. What architectural forms are about is Environmental Acquisition.

-----------------------------------------------------------------
Martin Bryan, 29 Oldbury Orchard, Churchdown, Glos GL3 2PU, UK
Phone/Fax: +44 1452 714029 E-mail: mtbryan@sgml.u-net.com
For more information about The SGML Centre contact http://www.sgml.u-net.com
For more information about the European Commission's Open Information Interchange (OII) initiative contact http://www.echo.lu/oii/en/oiistand.html


Return home to XML/EDI