Diamond Inheritance and Attribute Types in Timor
J. Leslie Keedy, Christian Heinlein and Gisela
Menger, University of
Ulm, Germany
Mark Evered, University of New England, Australia
|
 |
REFEREED
ARTICLE

PDF Version |
Abstract
In Timor multiple inheritance of methods from a common abstract ancestor
(e.g. Collection) and of separate "parts" (possibly repeatedly)
from distinct supertypes (e.g. a Radio, a Cassette Player) are handled
in different ways. The paper shows that neither technique is suitable
for cases where a common concrete ancestor (e.g. Person) is specialised
in different subtypes (e.g. as a Student, an Employee) and then brought
together in a new subtype, possibly with repeated inheritance (e.g.
a Doubly Employed Student). For such cases a new kind of type ("attribute
types") is proposed, which provides an alternative programming
paradigm to inheritance, based on the idea of adjectives and their
use in noun phrases in natural languages.
1 INTRODUCTION
Timor1 is a new OO language currently
being developed at the University of Ulm with the primary aim of facilitating
the development of programs
and applications using components which have been separately designed
and developed without knowledge of each other. In earlier papers two
different ways of handling multiple inheritance in Timor have been
presented.
The first paper [5] describes how subtypes in the Timor Collection
Library (TCL), such as Set, Bag and List, can be derived from a common
abstract ancestor (Collection). Multiple inheritance arises when
orthogonal properties (here the ordering and duplication of collection
elements)
are combined. In this case it is natural to merge methods (e.g. insert)
when they are inherited in a subtype from multiple supertypes at
intermediate levels in the hierarchy.
The second paper [10] addresses a completely
different kind of multiple inheritance, whereby a subtype (e.g. a type
RadioCassettePlayer) can
inherit "parts" from independent supertypes (e.g. a type
Radio and a type CassettePlayer). Repeated inheritance can play a significant
role (e.g. for a subtype RadioDoubleCassettePlayer), creating a naming
problem which Timor handles by allowing the supertypes to have "part
identifiers" in the subtype definition, thus giving them an appearance
analogous to variables declared by aggregation. The paper also discusses
in detail the differences between this kind of parts inheritance and
aggregation.
The present paper discusses the relationship between these
two fundamentally different approaches to multiple inheritance, using
examples which
involve a common ancestor (e.g. Person) that can be specialised in
orthogonal ways (e.g. as a Student and an Employee) and then brought
together in a subtype involving diamond inheritance (e.g. EmployedStudent),
and possibly also repeated inheritance (e.g. a DoublyEmployedStudent).
It will be shown that neither of the approaches described in the earlier
papers provides a satisfactory way of handling such examples.
A new
kind of type, called an attribute type, is then presented. Attribute
types support a programming paradigm which is based on noun phrases
in natural languages rather than on inheritance. This approach leads
to more modular units than conventional subtypes, and is especially
useful in cases which would otherwise result in diamond inheritance
problems. It is shown how different attributes can be flexibly mixed
and matched with a base object and can be composed in different combinations
(including cases which would otherwise lead to repeated inheritance)
into static type definitions.
The paper assumes a knowledge of the papers
mentioned above [5, 10] as well as an earlier paper which describes
the fundamentals of the
Timor approach to single inheritance [4]. The reader is advised that
the code re-use technique as described in [4, 5] has been revised to
take repeated inheritance into account. The new technique is described
in [10], and knowledge of this technique is assumed here.
Section 2
describes how types involving diamond inheritance can be defined in
Timor using a conventional OO style, and shows that with
the standard Timor re-use technique it is only possible to re-use an
implementation of one of the supertypes (cf. Java). Section 3 illustrates
that there is also a serious problem at the type level as soon as repeated
inheritance is considered. Section 4 then presents an alternative approach,
showing how attribute types (which can be compared with adjectives
in natural languages) can be defined and implemented. Then section
5 shows how these can be combined, using the analogy of adjectives
in noun phrases, to compose types involving diamond inheritance and
repeated inheritance (e.g. DoublyEmployedStudent). Section 6 shows
that the implementation difficulties encountered in section 2 do not
occur when attribute types are used, and section 7 shows that even
diamond inheritance types defined in the conventional way can be implemented
using implementations of attribute types, with full code re-use. Section
8 discusses the peculiarities of value and reference variables for
attribute types and section 9 describes casting of types containing
attributes. The paper then discusses related work in section 10 and
provides some concluding remarks in section 11.
2 DIAMOND INHERITANCE
We begin by considering a standard example
of diamond inheritance, showing how a type Person might serve as a
supertype from which types
such as Student and Employee can be derived and then combined into
an EmployedStudent. Type inheritance and code re-use are considered
in turn. The approach adopted in this section is based on the Timor
equivalent of the standard OO paradigm, as described in [5] (i.e. without
using part identifiers, but merging methods from a common ancestor).
Diamond
Inheritance at the Type Level
A type Person might be defined as follows:

This might have subtypes Student and Employee:

As would be expected, Student and Employee inherit
all the public methods and
abstract variables [6, 10] of Person, and redefine
the method toString.
A new type can be derived from
the above types, using diamond inheritance, to
model an EmployedStudent, as follows:

Because the type Person is inherited as a common ancestor via multiple
derived types (cf. Collection in [5, 6]) its inherited instance methods
and abstract
variables are merged in EmployedStudent. The method toString is redefined,
again as expected. If other Person methods were inherited in different forms
(as a
result of method redefinitions in Student and/or Employee)
a further redefinition of the affected methods would also be necessary in EmployedStudent.
At this
point it appears that an adequate mechanism for handling diamond inheritance
from a common concrete ancestor exists at the type level.
Diamond Inheritance
at the Implementation Level
Given an implementation of Person, the types
Student and Employee might be implemented along the following lines:

It might be thought that the combined type EmployedStudent can then
be implemented as follows:

This would provide an implementation which syntactically matches the
type definition: the methods of Person (except toString, which is implemented
explicitly in
the instance section) and of Student are all matched from Student
s, and the
remaining
Employee methods are matched from Employee
e.
But semantically the implementation would not achieve the
intended result, because it contains two separate Person implementations,
associated respectively
with
s and e, because each of these is a separate variable with its own complete
implementation (which by definition includes an implementation of Person).
In cases where subtype
methods access the supertype implementation (e.g. where Employee accesses Person),
the "wrong" Person state would be accessed.
We might attempt to solve
this problem by including an explicit variable for the "top" of
the diamond, e.g.

Even then an efficient implementation is not easy with the
means described in earlier papers, because any attempt to re-use
Student and Employee implementations
encounters the problem that these each still include a separate state for
its Person supertype.
A semantically correct implementation of EmployedStudent is always possible in Timor, because each implementation can be a fresh
implementation: there
is no
requirement that re-use variables must be used. But to recode each such case
from scratch, or to base a new implementation on the re-use of the code of
only one supertype (cf. the Java approach) is hardly satisfactory. Before
we present
a solution for this (implementation level) problem we consider repeated type
inheritance involving a common ancestor.
3 REPEATED INHERITANCE WITH A COMMON
ANCESTOR
Suppose the above example is changed so that it involves repeated
inheritance from a common ancestor, e.g. a DoubleStudent (i.e. a Person enrolled at two
universities) or a DoubleEmployee (i.e. a Person with two jobs). This might
be approached by
using part names (the Timor technique for achieving repeated inheritance
[6]). Here is a possible definition:

For this definition to be semantically appropriate (i.e. such that
it defines a single person with repeated Student but not Person attributes)
there would
have to be a rule requiring that a common ancestor inherited in multiple
parts leads to the merging of methods.
However, such a rule would be undesirable in other cases.
For example, suppose we extend the type CassettePlayer (defined in
[6]) to become
a CassetteRecorder,
as follows:

It would seem appropriate to define a DoubleCassetteRecorder (by analogy
with the DoubleCassettePlayer) as follows:
 But the intended interpretation, that there are two separate parts
each including its own supertype CassettePlayer conflicts with the
interpretation
appropriate
for DoubleStudent where the supertype Person should only be present once.
It
would no doubt be possible to devise mechanisms which could distinguish
between such cases, but these would all have at least one disadvantage.
Either the definer
of the repeated type would have to be aware of the way the individual supertype(s)
are defined, or (as with C++ virtual inheritance) a decision would have
to be made by the designers of all the second level types, perhaps even
before
the
diamond inheritance case is considered. The deeper the hierarchy involved,
the more evident it is that such approaches are unsatisfactory.
The Timor aims of supporting the information hiding principle
and of being able to use components without a knowledge of their inner
composition
led
to the decision
to adopt the interpretation of the above examples which replicates an entire
part without consideration of its inner structure or common ancestor(s)
(the interpretation relevant for DoubleCassetteRecorder), i.e. when multiple
subtypes
are inherited as parts, methods of a common ancestor are not implicitly
merged. According to this rule the type DoubleStudent defines a "schizophrenic",
with two Person elements.
An important additional advantage of this decision
is that it creates no implementation difficulties, as the following implementation
shows:

On the other hand all the difficulties associated with implementing EmployedStudent would
still arise for a rule which favours merging a common ancestor
in types such as this. 4 INHERITING ORTHOGONAL ATTRIBUTES
The above discussion leaves at
least two questions unanswered:
- How can repeated inheritance from
a common (shared) ancestor (such as a DoubleStudent)
be appropriately
defined at the type level?
- How can diamond inheritance and repeated
inheritance involving a common (shared) ancestor be conveniently implemented (even
where it can be appropriately
specified,
as in EmployedStudent)?
At the heart of these issues is the fact that
a (usually concrete) base type serves as a common (shared) ancestor
which can be orthogonally extended
in
a potentially infinite number of ways to specialise objects of the base
type. Such
orthogonal attributes can then be combined (and might occur repeatedly)
in particular objects. Person is not an exception in this respect. The
same
principle would
apply to a hierarchy defining ships or vehicles, and many other cases.
Such specialisations are usually incremental extensions
which are behaviourally conform with the base type (cf. [11]), i.e.
they typically add new state
and new methods, without changing the definition of existing methods
or state. In fact they are normally not only behaviourally conform with
their
supertype
but,
for a given supertype, they are usually compatible with each other. (In
the above example the method toString appears to be an exception, but
this will
be taken
into account in the following discussion.)
To handle such extensions Timor
breaks with the standard OO paradigm, by providing a mechanism for
defining behaviourally compatible type units
as add-on attributes,
which can be orthogonally combined with each other in association with
a base type. This alternative paradigm is inspired by the use of adjectives
in natural
language rather than by inheritance concepts. Adjectives (cf. attributes)
can be added to nouns (cf. objects) to augment their meaning (e.g. a
student
is
a studying person, an employee is an employed person,
an employed student is a
studying, employed person). In contrast inheritance simply works in terms
of nouns (i.e. objects, e.g. a student is a person), with the consequence
that
in the object oriented paradigm the attributes represented by adjectives
simply disappear as separate units. This is unfortunate, since adjectives
are especially
flexible: the same adjective can often qualify many different nouns,
and many different adjectives can (where appropriate concurrently) qualify
the
same
noun.
The basic idea behind attribute types in Timor is to introduce a similar
level of flexibility into programming. This involves constructs for defining
and
implementing attribute types (i.e. the adjectives) and further constructs
allowing them to
be composed into more complex types (i.e. the noun phrases).
In this section
it is shown how such attribute types can be defined and implemented
in Timor, and in section 5 how they can then be composed
into new types.
Attribute Type Definitions
An attribute type definition is characterised
by the keyword for. The for clause
nominates a base for the attribute type (known as an attribute
base2). This
can be defined in terms of a type, or a view, or the special keyword
any, and indicates
the type(s) of object which can be qualified adjectivally. In the following
examples a specific type is nominated as the attribute base.

Although attribute types have a similar appearance and serve a similar
purpose to subtypes, they are by no means the same. Here are some key
differences from the viewpoint of type definition and implementation:
- An attribute type can have only one attribute base3.
- The methods of the attribute base cannot be redefined in a redefines clause
of an attribute type4.
- The attribute
type's makers, if any, are responsible only for initialising
their own state. They cannot invoke the makers of the attribute base.
- The instance methods of an attribute type can access the public methods
of the associated base object via a pseudo variable base.
This promotes
both behavioural
conformity with its attribute base and independence of the latter's
implementation.
- The instance methods of an attribute type should
confine their activities to the attribute's own state. Thus methods
such as toString should
produce results which can be used to add to (rather than already
include) those
of the attribute
base in a modular way.
In accordance with the philosophy behind attribute
types we typically use adjectival names in examples.
Implementing Attribute
Types
Like other Timor types, attribute types can have multiple implementations.
Their implementations differ from implementations of other types only
in that the code
of their methods can use the pseudo variable base,
which provides access to the public methods of the attribute base object.
Here is an implementation
of Studying:

The code of the method ageAtMatriculation illustrates how the pseudo
variable base can be used to gain access to the public methods of the
base object
(here the get method of dob from Person, using the abstract variable
notation, cf.
[6, 10]).
Because of its add-on nature, an implementation of an attribute
type does not include state variables describing its attribute base.
Inheriting
from Attribute Types
Like other Timor types, attribute types can inherit
(in the conventional sense) from other types. Inherited bases may (but
need not) be attribute
types. If
one or more of the inherited bases is an attribute type, then the subtype
must have
an attribute base which is either the same type as, or is a common
subtype of, all the attribute bases of the inherited types.
5 USING
ATTRIBUTES IN TYPE DEFINITIONS
In concrete situations adjectives are
used to qualify nouns, typically in noun phrases. Similarly, instances
of attribute types ("attributes") can
be used in association with their base objects to compose new types.
In this section we consider how such types are composed.
Composing Types from Attributes
The following is an alternative
definition of EmployedStudent which uses
attribute types.

The extends clause defines one or more inherited
bases, as usual. Those bases which serve as attribute bases are preceded
by a bracketed
list
of dependent
attributes. The methods of the attribute base (here Person)
and of the individual attributes (here Studying and Employed)
are all "inherited" as
separate methods of the new type.
The syntax can be understood in terms
of the following EBNF fragment:

This syntax is more
fully explained in [9], which also describes how it can be used in static definitions
that include qualifying types with bracket
methods [7, 8]. The basic idea is that a qualified item can be qualified
by a qualifying
list (here of attributes). Because the qualifying list is recursively
defined in terms of a qualified list, qualifying items (here attributes)
can themselves
be qualified.
Because each of the attributes and the attribute base
in this example all have a method toString, a name collision occurs,
which, if unresolved,
would lead
to a compile time error. Hence this appears in a redefines clause
to indicate
that it is a common method (with an informal specification indicating
what it does)5.
The instance methods and abstract variables of AttributedEmployedStudent are identical to those of the conventional EmployedStudent, as follows:

Should the
designer of the type wish to make the individual toString methods of
the various parts publicly available as separate methods,
this can be
achieved by adding part names (which may be defined as optional,
cf. [10]), e.g.

In this case there are separate public methods s.toString, e.toString,
p.toString and toString. Because the part names have been provided
in the optional form,
non-colliding methods can be invoked by the client either with or
without the part name (cf. [6]). This type is not equivalent to EmployedStudent.
Repeated
Attributes
The modular structure of attribute types allows diamond and
repeated inheritance to be simulated in a straightforward manner, e.g.

This is defined by analogy with repeated inheritance of parts. Repeated
attributes must have a part name; others (including the attribute
base) may, but need
not be explicitly named. Part names must be provided whenever a type
occurs more
than once in the derivation clauses of a type definition. These must
be unique within all the derivation clauses of a type definition
and cannot
be hierarchical
(i.e. their uniqueness must be independent of the dot notation).
Part names are used by clients to invoke methods, as in
simple repeated inheritance (except in cases where they are optionally
defined using
square brackets
[10]). Where a part name is used, the names of the object's members
are compounded from the part name and the normal method name, using
the dot
notation, e.g.

In DoublyEmployedStudent the toString methods of all the constituent types are merged into a
single method. As in the case of repeated
parts inheritance,
any
named parts must be explicitly named in the redefines clause if their
methods are to be merged. The effect of omitting the part names from
the redefines clause would be that the methods toString from Studying and Person would be merged,
but the methods e1.toString and e2.toString would remain separate
methods for objects of type DoublyEmployedStudent.
The parameters
of makers may (but need not) use the dot notation to name parameters,
where this corresponds to a name as seen by the
client.
This
facility allows
simple makers with parameters to be implemented automatically.
Multiple
Attribute Bases
The extends clause is a normal extends clause. Consequently
an attribute base is simply an inherited type (or part), and types
can be defined
to extend or
include multiple attribute bases. Here is an example defining a "schizophrenic",
whose first personality thinks he is a student while the second thinks
he is doubly employed:

In this example there is no method toString, but there are methods
known to the client as p1.toString and p2.toString.
Bases for Attribute
Types
A for clause can nominate a type as its
attribute base, as in the above examples, or it can nominate a view
(cf. [6]), in which case
an instance
of any type
which implicitly or explicitly contains this view can serve as a
base type. In both
cases the compiler checks that instances of the attribute type are
only used in conjunction with bases which contain the view or type
named in
the for clause.
Alternatively an
attribute type can be defined to have the special base any, which
indicates that it can have any type as an attribute
base.
In this case
its implementations may not use the pseudo variable base. Here is
an example:

The for any clause indicates that instances of this type should only
be used in conjunction with an attribute base, even though implementations
may not
use the pseudo variable base.
Attribute Types as Attribute Bases
An attribute type can qualify another
attribute type. This is equivalent to qualifying an adjective with
an adverb. Thus an attribute PartTime might be
defined as follows:

This could be used in a type:

Here the first personality is a part-time student, while the second
has a part-time employment e1 and an employment e2 not defined as
part-time. The
items PartTime,
Employed and Person must have part names, because of the type repetition,
but Studying need not. In the latter case the member names "belong
to" the
next named higher part in the hierarchy. In this example there is,
for instance, an abstract variable in Studying named p1.uni. The
client refers to the methods
in the PartTime items as pt1.fractionPartTime and pt2.fractionPartTime,
e.g.

6 IMPLEMENTATIONS USING
ATTRIBUTE TYPES
Automatic Implementations
Assuming that implementations for all the
types used in derivation clauses (see section 5) already exist, it
would be tedious to require
the programmer
to provide
explicit implementations of types into which they are composed, especially
if no methods are being overridden and no new methods are being added.
For such
cases, if there are no explicit makers (or if the makers conform
to certain requirements), the compiler can provide an automatic implementation
of
the type in question.
It transforms the type definition using the following basic rules:
- Change each extends or includes clause into a state clause.
- For each
type which does not already have a part name in the type definition,
add a part name (the same as the type name, but beginning
with a small
letter) to form a variable declaration.
- For each type which already
has a part name in the type definition, use that part name to form
a variable declaration.
- Prefix the hat symbol to each type name of
a variable declaration which provides public methods.
- Add a parameterless
maker or makers which conform to the requirements for producing
automatic makers.
The following is an automatic implementation of the type SchizoPartTimeDoublyEmployedStudent (cf. the last subsection of section 5):

This automatic implementation sets out a pattern which can be used
in explicit implementations. The key points which it illustrates
are as
follows:
- Qualified lists can be used in the state section of an
implementation to express the relationships between attributes
and their attribute
bases.
- Each variable has a unique name.
- Makers of attributes are invoked
from within the maker for the composed type to instantiate the
necessary attributes.
- Makers conforming to simple rules with respect to their
formal parameter names can be implemented automatically.
Explicit Implementations
We now show how an explicit implementation
might handle a redefined method. To illustrate this we implement the
type DoublyEmployedStudent (defined
in section
5 using attribute types):

In accordance with the Timor strategy that any type can be implemented
from scratch, there is no necessity that a type defined in terms
of attributes must be implemented
using attribute types. However, if implementations of attribute types
are used in an implementation of some other type the programmer must
define
these
using
qualified lists, in order to clarify the relationships between attribute
implementations and their attribute bases.
7 IMPLEMENTING CONVENTIONAL DIAMOND INHERITANCE VIA ATTRIBUTES
In
the implementation discussion in section 2, which was based on a conventional
approach to inheritance, we did not find a straightforward
solution for
implementing diamond inheritance with more than one re-use variable.
However, the previous
sections have illustrated that no substantial problems arise when
attributes
are used to achieve the equivalent of diamond inheritance.
Because of the relative independence of type definitions
and implementations, attribute implementations can be used not only
to implement types
defined using attributes but also to implement types defined in the
conventional
diamond
inheritance style, such as EmployedStudent. The following type definition
remains unchanged
from section 2. It does not include attribute types.

Here is an implementation, using attribute implementations defined
previously:

The Person methods are matched from the re-use variable ^Person
p,
while the additional Student and Employee methods are matched from
(any implementation
of) the re-use variables ^Studying s and ^Employed
e. Although these
are different
types from those used in the type definition (i.e. Student and Employee)
the instance methods match and so are selected.
The fundamental difference from the attempted diamond inheritance
implementation in section 2 is that in contrast with implementations
of Student and
Employee implementations of Studying and Employed do not include
state for Person.
Consequently the problems encountered earlier do not arise.
Although
the individual toString methods have been merged into a single redefined
method, they still exist in the re-use variables
representing
the attributes
and their base, and can still be invoked in implementations which
re-use them, as is illustrated in the implementation of the redefined
toString.
8 ATTRIBUTE VALUES AND REFERENCES
The peculiarities of attribute
types lead to some special rules with regard to attribute values and
attribute references.
Attribute Values
An attribute (instance) relies logically and if it
uses the pseudo variable base also physically
on the existence of its attribute base,
which implies
that an
attribute cannot simply be instantiated as a free-standing object
or value. Consequently it is inappropriate to allow attributes to
be declared
as
free-standing value
variables in implementations (or as abstract values in type definitions).
Hence value declarations of attribute types are permitted only as
items in qualifying
lists. A simple declaration such as

is treated as a compile time error.
Attribute References
Like a view, an attribute type provides instance
methods which are a subset of the instance methods of objects in which
it is embedded.
Consequently
it can
be useful to allow reference variables to refer to an existing attribute.
Hence it is permitted to declare an attribute reference, e.g.
 Such reference variables, like reference variables for supertypes
and views, refer to the entire object in which the particular attribute
is embedded,
and can therefore be the subject of cast statements (see section
9).
Because of the need to guarantee the existence of a base, such
a reference cannot be used to instantiate an actual attribute as such,
i.e. the
compiler would treat
a statement such as:

as an error, but it would allow
statements such as

Unlike a view, an attribute
type cannot be defined retrospectively, so that a statement such as
the latter would not be valid merely
on the
basis of
matching methods. Thus an assignment statement
 is erroneous, because the type EmployedStudent is defined in terms of Employee, not Employed, whereas

is valid.
9 THE CAST STATEMENT
An object is considered to be behaviourally conform with any attribute
bases which it extends (but not includes) and it can therefore be
used polymorphically,
where appropriate using part names to identify which attribute base
is intended, e.g.

As in the cases of normal inheritance
and parts inheritance, such an assignment logically assigns the entire
object (not merely the
part)
to the reference.
The Timor conditional downcast statement can then be used in the
usual way to gain
access to the entire subtype, e.g.

The cast statement
can also be used to access attributes contained in an object, and where
appropriate the square bracket notation can
be used
to
gain access
to multiple attributes of the same type (cf. repeated parts [10]),
e.g.

As this example illustrates, nested cast statements can be used to
access (depth first) all the attributes in an object in succession.
Where cast
statements are nested in this way all references in the current hierarchy
are accessible.
Thus
the statements associated with PartTime pt can use the current values
of pt,
e and p as references (unless they have been hidden by other in scope
references which use the same identifiers).
Finally a conditional
cast can be applied to an attribute reference in order to gain access
to an underlying object or, as in this example,
other attributes
in the object:

10 RELATED WORK
In 1997 members of our group published a paper entitled "Attribute Types
and Bracket Implementations" [3] which presented in outline ideas
developed for the experimental language L1. The paper outlined in nascent
form the basic
concepts both of Timor attribute types, presented in the present paper,
and of Timor qualifying types (cf. [7, 8]). Although the ideas for
both have since been
considerably refined and improved for Timor, the idea that a programming
language should support not only types based on nouns but also further
types based on
adjectives, together with a technique allowing new types (corresponding
to noun phrases) to be composed from these, was already emphasized
in that paper.
Others have also pointed out that the object oriented paradigm
could be enriched by taking adjectives more seriously (e.g. [1, 2])
but
have not
described
a technique for doing this corresponding to attribute types.
The need
for adjectival types in the object oriented paradigm has become visible
partly through Java interfaces and the tendency to
name some
of these adjectivally,
e.g. Runnable, Serializable. However, in contrast with Timor's attribute
types, Java interfaces do not provide a solution with full code re-use
for diamond
inheritance from a common concrete ancestor nor a solution to repeated
inheritance involving
a common concrete ancestor.
11 CONCLUSION
The paper has presented some aspects of an alternative
programming paradigm to inheritance, based on the idea of adjectives
in natural
language.
In doing so
we have shown that the technique can easily master issues such as
diamond inheritance and repeated inheritance from a common concrete
ancestor.
This technique can
be used in Timor to complement both the conventional object oriented
programming paradigm (which can be effectively used for subtyping
involving single
inheritance and cases of multiple inheritance from a common abstract
ancestor) and the
parts inheritance technique (which is especially suitable for repeated
inheritance and for multiple inheritance from distinct concrete types).
Attribute
types have two significant characteristics: they are very modular
units and they cannot redefine the methods of their attribute
base type.
It is these
features which allow them to be easily mixed and matched to compose
new types, as we have described in the paper. But these characteristics
endow
them with
a further advantage: such mixing and matching need not be limited
to static type definitions. In a future paper we will show how
individual attributes
can be
dynamically added at run-time to appropriate attribute base objects,
thus allowing, for example, a Person object to change its specialisations
dynamically
over
time. In this sense attribute types should make Timor especially
attractive
for data
base applications in which objects need to change over time to
reflect changes in the world which is being modelled.
Finally we point out
that the other "adjectival" form of
type in Timor, qualifying types, can also be statically defined,
and in fact the same rules
as we saw in section 5 for composing attribute types into new types
are used for qualifying types. Because the rules required for qualifying
types are somewhat
more complex (in view of the existence of bracket methods) we have
deferred a full discussion of that syntax until a later paper in
which statically defined
qualifying types are presented.
ACKNOWLEDGEMENTS
Special thanks are due to Dr. Axel Schmolitzky for
his invaluable contributions to discussions of Timor and to the ideas
which have
been taken over
from earlier projects. Without his ideas and comments Timor would
not have
been possible.
Footnotes
1 see http://www.timor-programming.org
2 As
will become clear, this differs from the bases from which a type
can inherit (in Timor using the keywords extends and/or includes) in
the
conventional OO
sense. We refer to such bases as inherited bases.
3 It can however be defined
to extend and/or include other types in the usual way.
4 It can however
have a redefines section in which methods of its inherited bases
can be redefined.
5 Although an attribute type may
not redefine the methods of its base type, the designer of a type which
composes an attribute
type with
its attribute
base
can make such redefinitions. REFERENCES
[1] M. C. Feathers, "Factoring Class Capabilities with
Adjectives," Journal
of Object Oriented Programming, vol. 12, no. 1, pp. 28-34, 1999.
[2]
I. Forman and S. Danforth, Putting Metaclasses to Work. Reading, MA.
Addison-Wesley, 1998.
[3] J. L. Keedy, M. Evered, A. Schmolitzky, and
G. Menger, "Attribute Types
and Bracket Implementations," 25th International Conference
on Technology of Object-Oriented Languages and Systems, Melbourne,
1997,
pp. 325-338.
[4] J. L. Keedy, G. Menger, and C. Heinlein, "Support
for Subtyping and Code Re-use in Timor," 40th International
Conference on Technology of Object-Oriented Languages and Systems
(TOOLS Pacific 2002), Sydney,
Australia, 2002, Conferences
in Research and Practice in Information Technology, vol. 10, pp.
35-43.
[5] J. L. Keedy, G. Menger, and C. Heinlein, "Inheriting
from a Common Abstract Ancestor in Timor," Journal of Object
Technology, vol. 1, no. 1, May 2002, pp. 81-106. http://www.jot.fm/issues/issue_2002_05/article2.
[6] J. L. Keedy, G. Menger, and C. Heinlein, "Taking Information
Hiding Seriously in an Object Oriented Context," Net.ObjectDays,
Erfurt, Germany, 2003, pp. 51-65.
[7] J. L. Keedy, G. Menger, C.
Heinlein, and F. Henskens, "Qualifying Types
Illustrated by Synchronisation Examples," in Objects, Components,
Architectures, Services and Applications for a Networked World, International
Conference NetObjectDays,
NODe 2002, Erfurt, Germany, vol. LNCS 2591, M. Aksit, M. Mezini,
and R. Unland, Eds.: Springer, 2003, pp. 330-344.
[8] J. L. Keedy,
K. Espenlaub, G. Menger, and C. Heinlein, "Qualifying Types
with Bracket Methods in Timor," Journal of Object Technology,
vol. 3, no. 1, January-February 2004,
pp. 101-121. http://www.jot.fm/issues/issue_2004_01/article1
[9] J. L. Keedy, K. Espenlaub, G. Menger, and C. Heinlein, "Statically
Qualified Types in Timor," (submitted for publication), 2004.
[10]
J. L. Keedy, G. Menger, and C. Heinlein, "Inheriting Multiple
and Repeated Parts in Timor," Journal of Object Technology,
vol. 3, no. 10, November-December 2004, pp. 99-120. http://www.jot.fm/issues/issue_2004_11/article1
[11]
B. Liskov and J. M. Wing, "A Behavioral Notion of Subtyping," ACM
Transactions on Programming Languages and Systems, vol. 16, no. 6,
pp. 1811-1841, 1994.
About the authors
 |
|
J. Leslie Keedy is Professor and Head, Department of
Computer Structures, University of Ulm, Germany, where he leads
the Timor language design and the Speedos operating design groups.
His email address is keedy@informatik.uni-ulm.de.
His biography can be visited at http://www.informatik.uni-ulm.de/rs/mitarbeiter/jlk/
|
 |
|
|
 |
|
Gisela Menger received a Ph.D. in Computer Science from
the University of Ulm in 2000. Currently she works as a scientific
assistant in the Department of Computer Structures at the University
of Ulm. Her research interests include programming language
design and software engineering. Her email address is menger@informatik.uni-ulm.de.
|
 |
|
|

|
 |
Christian Heinlein received a Ph.D. in Computer Science
from the University of Ulm in 2000. Currently, he works as a
scientific assistant in the Department of Computer Structures
at the University of Ulm. His research interests include programming
language design in general, especially genericity, extensibility
and non-standard type systems. His email address is heinlein@informatik.uni-ulm.de.
|
 |
|
Mark Evered is a Senior Lecturer in
the School of Mathematics, Statistics and Computer Science at
the University of New England in Armidale, Australia. He completed
his PhD at the Technical University of Darmstadt in Germany. His
research interests include Object-based Systems, Security, Persistence
and Programming Language Design and Implementation. His email
address is: markev@mcs.une.edu.au. |
Cite this article as follows: Leslie Keedy, Christian Heinlein, Gisela
Menger, Mark Evered: “Diamond Inheritance and Attribute Types
in Timor”, in Journal of Object Technology, vol. 3,
no. 10, November-December 2004, pp. 121-142. http://www.jot.fm/issues/issue_2004_11/article2
|