Genericity and Virtual Types (VTs),
design patterns, and frameworks
1. Introduction
Design patterns
[8] *) **) and
frameworks are frequently represented by groups of cooperating, interdependent
classes that reference each other and that have to be specialized/derived
collectively in a consistent way in order to be used in actual
applications. The term "framework" refers to the overall, top-level structure
of entire applications while "design patterns" may also deal with groups of
lower-level interdependent "generic utility classes" that may be specialized
for concrete usage. Although the definition of design patterns would be given
in natural language, perhaps enhanced by sketchy sample programs in a concrete
programming language, it would be highly desirable to provide immediately
reusable versions of design patterns in concrete programming languages like Lava.
The widespread programming languages, however, do not provide proper
expressive means for implementing concrete incarnations of design patterns.
Parameterized classes as the "templates" of C++ or the
"generic classes" of Eiffel do not meet the
requirements: They can be viewed as special macros or as type generation
constructs having three serious drawbacks:
- They do not properly describe parameterized groups of
interdependent classes but mainly single parameterized classes.
- They do not provide a derivation mechanism that allows you to derive
specialized classes from those parameterized templates or generic
classes.
- The older implementation techniques (C++)
entail code replication rather than code reuse and thus are prone to blow
up the program sizes as well as the time required for
compilation/linking.
For the design of Lava we have drawn the following
conclusions from this situation and from the fact that we have a package notion in Lava
anyway that allows us to form groups of related classes or other
declarations:
- Lava introduces patterns as packages or classes with
named type parameters ("pattern parameters" or "virtual types", short: VT). Packages/classes with
VTs are called "patterns" since they are used to provide concrete
implementations of design patterns in Lava.
- The value of a VT may designate a Lava class or another
VT that is visible at this place (see 8. below). A VT of a class may in
particular designate its containing class and serve as a Lava substitute for the ThisType or MyType of other VT
proposals.
- A virtual type may also be "abstract".
Then its value is "void"; a non-void value may be assigned when overriding
the abstract VT in a derived pattern.
- A VT v of a package/class P1 may be overridden in a
derived package/class P2 by assigning a new value nv to it,
which has to be derived from the value of v in the base
package/class (except if v is abstract there). To override v you
select it in the override view of P2 and
proceed as described in the pertinent section.
- If a class A is declared within a pattern P then it can be
extended only within P or within patterns derived from P.
(This condition could possibly be weakened, but that would complicate the
implementation as well as the rules that have to be obeyed by the
programmers. The present wording just reflects the fact that the values of
the VTs that may be referenced in A or its extension are defined only
within P or patterns derived from P.)
- Classes from more derived patterns cannot be used in base patterns.
- VTs may be used to declare the types of local and member variables as
well as of function arguments : Their actual, concrete types depend on the
respective "pattern context" (see also 10. below). In the
literature this is called "covariant specialization".
- The "visibility" of VTs is restricted in
the following way: They are visible in the containing package or class
where they are introduced. If they are visible in a class A then
also in every nested declaration and in every implementation of A.
If they are visible in a class or package P then also in every
class/package derived from P unless they are overridden there.
Classes declared in a pattern P' that is derived from P
cannot be referenced in P.
- If a class A is the value of a virtual type
V then A cannot be referenced directly at any place where
V is visible. It can only be referenced indirectly by references to
V in these places. If A1 is derived from A within the same pattern,
then A1 cannot be referenced directly, either. (A motivation of this rule
is given in our IsSelfVirtual
sample.)
- Lava restricts the ways in
which pattern declarations may be nested: There may be only two nested
layers of packages or classes containing virtual types. (The VT
implementation costs would be considerably higher if nesting of VT layers
to any depth would be allowed.) The lower layer is called the "inner
pattern context", the higher one the "outer pattern context" of
the declarations belonging to or nested in the lower layer. Generally, the
term "pattern context of a declaration" designates the combination
of the inner and outer pattern context.
- Lava supports multiple inheritance not only on
the class level but also on the package level: A package may be derived
from one or several other packages. Non-overridden virtual types from
immediate or indirect base patterns are inherited and visible also in the
derived pattern.
- If a pattern P1 references a type T2 that is the value of a
virtual type of a separate pattern P2 and a third pattern P3
is derived from P1 and P2, then the reference to T2 is
still treated as an "external" rather than as a virtual type reference
(although T2 belongs to the context of common derived pattern
P3 now).
- Lava maintains the classical view of parameterized
types (like C++ templates) insofar as it considers two instantiations of
the same type in different pattern contexts to be incompatible.
The currently valid value of a pattern parameter or "virtual type
(VT)" is taken at run time from a "virtual type table (VTT)" similar
to the usual "virtual function table (VFT)" of object-oriented
programming systems. As usual, Lava provides for every Lava object a pointer to its associated VFT, but additionally
also a pointer to an associated VTT. Like the VFT, the proper VTT is determined
on object creation, roughly spoken as the "pattern context" of its
implementation, and this is in turn the pattern context of the class that the
latter implements.
Generally, we use the term type for a concrete class or a
virtual type / pattern parameter in the sense explained above. (Both may
be referenced as types of variables in Lava programs.)
A type is called a multiform type if it is
either a virtual type or a class that is declared within a pattern. The meaning
of a multiform type may depend on the pattern context where it is used. We use
"uniform" as a synonym for "non-multiform".
Virtual types may be referenced anywhere (on any nesting level) within their
"owner" package or class, but also in implementations of classes belonging to
that scope. (These implementations may be located even outside this scope.)
Summary: A Lava pattern is just a quite normal package or
class declaration, having virtual types.
2. Representation and specialization of patterns in LavaPE
In the Lava declaration view a
pattern is just a quite normal package or class declaration, having virtual types (VT). A virtual type vt has a name and a value VAL(vt). The value
may be a class (having the name of the virtual type) or the name of another VT.
(The term "bound" is also used in the literature for the
value of a VT.)
A virtual type may also be "abstract". Then its value is "empty";
a non-empty value may be assigned when overriding the abstract VT in a derived
pattern.
A VT is called "final" if its value is a class. This class cannot
be referenced then as a normal class within the containing pattern; its name
rather denotes the VT whose value it is. Outside the pattern, it denotes just
the class.
Moreover, classes (and virtual types anyway) of a derived pattern
P cannot be referenced in base patterns of P.
A VT has a name and a value. The value may be (the name of) a
class or of another VT. A virtual type may also be "abstract". Then its value
is "empty"; a non-empty value may be assigned when overriding the abstract VT
in a derived pattern.
Generally, package and class declarations may be
nested to any depth in Lava (but class declarations
cannot contain nested package declarations). For packages and classes with
virtual types the above-mentioned restrictions
apply, however.
Specialization of patterns makes use of the same Lava override view that is also
used for quite normal class derivation.
3. Static type-safety of Lava, related work
A special section of this documentation has
been dedicated to the static type-safety of Lava. The
relation of our approach to other notions of virtual types is discussed here. An outline of the proof of the static type-safety of Lava can be found at the same place.
See also:
Patterns and type casts
Pattern samples