[Archive copy mirrored from the URL: http://www.geocities.com/WallStreet/Floor/5815/ooxmledi.htm; see this canonical version of the document.]
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.
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.
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".
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.
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.
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.
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.
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.
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 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 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 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.
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. :)
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