tion; thus, with this respect, the generics presented in
this paper are related to C++ templates, rather than
to Java generics. The generics needed in the con-
text of Smalltalk act at a meta-level, by generating
new classes starting from existing ones, thus, they
have similarities with generative programming mech-
anisms (Eisenecker and Czarnecki, 2000) and C++
meta programming (Abrahams and Gurtovoy, 2004).
This meta programming mechanism is evident also in
our generics and reverse generics implementation in
Pharo: new code is generated starting from existing
one, without modifying the latter. This takes place in
two steps: with reverse generics a brand new generic
version is obtained starting from existing code; then,
by instantiating generic classes, the generic code is
adapted and reused in a new context.
There seem to be similarities among reverse
generics and some refactoring approaches: however,
the intent of reverse generics is not to perform reverse
engineering or refactoring of existing code, (see, e.g.,
(Duggan, 1999; Dincklage and Diwan, 2004; Kiezun
et al., 2007)) but to extrapolate possible generic “tem-
plate” code from existing one, and reuse it for gener-
ating new code. Note that this programming method-
ology will permit modifying only the original existing
code, and then, automatically, spread the modifica-
tions to the one obtained by reverse generics.
A first attempt to automatically extract generic
class definitions from an existing library has been
conveyed by Duggan (Duggan, 1999), well before the
introduction of generics into Java. Besides the reverse
engineering aspect, Duggan’s work diverges from re-
verse generics regarding downcast insertion and pa-
rameter instantiation. Duggan makes use of dynamic
subtype constraint that inserts runtime downcasts. A
parametrized type may be instantiated, which requires
some type-checking rules for the creation of an ob-
ject: the actual type arguments must satisfy the up-
per bounds of the formal type parameters in the class
type.
Kiezun et al. propose a type-constraints-based al-
gorithm for converting non-generic libraries to add
type parameters (Kiezun et al., 2007). It handles the
full Java language and preserves backward compati-
bility. It is capable of inferring wildcard types and
introducing type parameters for mutually-dependent
classes. Reverse engineering approaches ensure that
a library conversion preserves the original behavior of
the legacy code. This is a natural intent since such a
conversion is exploited as a refactoring. Instead, the
purpose of reverse generics is to replace static types
references contained in existing classes with special-
ized ones and then to produce a brand new class.
A limitation of first-order parametric polymor-
phism is that it is not possible to abstract over a type
constructor. For instance, in List<T>, List is a type
constructor, since, given an argument for T, e.g., Inte-
ger, it builds a new type, i.e., List<Integer>. However,
the type constructor List itself is not abstracted. There-
fore, one cannot pass a type constructor as a type ar-
gument to another type constructor. Template tem-
plate parameters
8
(Weiss and Simonis, 2001) in C++
provides a means to abstract over type constructors.
Moors, Piessens and Odersky (Moors et al., 2008) ex-
tended the Scala language (Odersky et al., 2008) with
type construction polymorphism to allow type con-
structors as type parameters. Therefore, it is possible
not only to abstract over a type, but also over a type
constructor; for instance, a class can be parametrized
over Container[T]
9
, where Container is a type construc-
tor which is itself abstracted and can be instantiated
with the actual collection, e.g., List or Stack, which are
type constructors themselves. The generics mecha-
nism presented in this paper acts at the same level of
first-order parametric polymorphism, thus, it shares
the same limitations. An interesting extension would
be to be able to switch to the higher level of type con-
structor polymorphism, but this is an issue that still
needs to be investigated.
The Dependency Injection pattern (Fowler, 2004)
is used to “inject” actual implementation classes into
a class hierarchy in a consistent way. This is useful
when classes delegate specific functionalities to other
classes: messages are simply forwarded to the object
referenced in a field. These fields will have as type
an interface (or a base class); then, these fields will be
instantiated with derived classes implementing those
interfaces. This way the actual behavior is abstracted,
but we need to tackle the problem of “injecting” the
actual implementation classes: we do not have the im-
plementation classes’ names hardcoded in the code of
the classes that will use them, but we need to initialize
those classes somewhere. Moreover, we need to make
sure that, if we switch the implementation classes, we
will do that consistently throughout the code. Typi-
cally this can be done with factory method and ab-
stract factory patterns (Gamma et al., 1995), but with
dependency injection frameworks it is easier to keep
the desired consistency, and the programmer needs to
write less code. The reverse generics mechanism is
not related to object composition and delegation, i.e.,
the typical context of the inversion of control philoso-
phy that dependency injection tries to deal with. With
reverse generics the programmer does not have to de-
sign classes according the pattern of abstracting the
actual behavior and then delegate it to factory meth-
8
The repetition of “template” is not a mistake.
9
Scala uses [] instead of <>.
ICSOFT2012-7thInternationalConferenceonSoftwareParadigmTrends
370