casts redundant (Mahmoud, 2004). Java Generics
was designed with the Collection classes in mind,
where
Object
is used as the common type of ele-
ments in collections. To maintain backward compat-
ibility to older Java libraries, Java Generics was de-
signed and implemented by type erasure. This results
in equal runnable code for both traditional Java syn-
tax and Java with generics. The Java compiler ac-
complishes this by replacing the type parameters by
Object
and inserting casts whenever necessary (Naf-
talin and Wadler, 2007).
Implementation by erasure gives some restrictions
(Bracha, 2004). Since we do not have any represen-
tation of the generic types on runtime, we cannot in-
stantiate new objects of type parameters, or make ar-
rays of type parameters. We shall see later that these
restrictions can be a problem if we extend traits with
Java Generics.
3.2 Templates
Templates (as found in C++)are similar to Java Gener-
ics both in syntax and w.r.t. the representation at run-
time. When using templates, type parameters will
be replaced by the actual types by a preprocessor.
Since this is done before we run the Java compiler,
we have more flexibility on how this replacement is
done. For instance we are able to instantiate new ob-
jects from type parameters, because type parameters
are replaced with actual types before the instantiation
is done.
One may question how well the semantics (or
lack) of C++-like templates conform with Java. How-
ever, we believe that templates can solve many of the
issues, and there this an viable alternative.
3.3 Virtual Types
The concepts of virtual types was introduced in the
language Beta as virtual patterns (Lehrmann Madsen
and Mller-Pedersen, 1989), and later considered for
Java (Thorup, 1997). The semantic rules of virtual
types are similar to the rules of virtual methods. A
virtual method is first defined as general as possible in
a general class, and can then in subclasses of this gen-
eral class be redefined when we have more informa-
tion about what functionality we need. The concept
of a virtual type is similar: We first define a general
type, and redefine it in subclasses to a more specific
type.
Since we do not have support for virtual types in
Java, we have to replace all virtual types with their
redefinition types during the flattening process. This
results in a mechanism which is practically similar to
templates. The main difference is how and when the
actual types are specified. This will be discussed fur-
ther in section 5.2.
4 IMPLEMENTATION OF
GENERIC TRAITS IN JAVA
To be able to compare the three generic mechanisms
and to illustrate the differences between them, we
have developed a preprocessor for Java with generic
traits. The preprocessor is divided into three parts:
Parsing, flattening and Java code generation.
To handle the parsing process and to automati-
cally generate an abstract syntax tree (AST), we used
AntLR (http://www.antlr.org/). We used an already
available grammar (Studman, 2005), and extended
this grammar with the necessary syntax for traits.
We found it convenient to develop a data structure
that models the trait hierarchy. This structure con-
tains functionality for getting information about the
traits and relations between them. This makes it eas-
ier to perform the flattening process, especially since
we want to do this in two ways.
The code generator is basically a pretty printer
which outputsstandard Java code. It traverses the syn-
tax tree, but does not print any node that is part of the
annotated trait syntax.
4.1 Two Flattening Strategies
We have examined two strategies for flattening (see
Figure 5). The first one, which we have called Classic
Flattening, is the strategy described in (Ducasse et al.,
2006), (Nierstrasz et al., ), (Sh¨arli et al., 2002) and
(Reichhart, 2005), and involves moving every method
of trait into the class that use the trai. This means
that the trait blocks will be redundant, and are thus
removed from the processed program.
The other strategy, which we have named Object
Flattening, is a fairly different approach. Instead of
moving every trait method into the class, we keep
the trait blocks (as objects) and make references from
the class to the trait block. To be able to keep the
trait block in traditional Java syntax, we convert the
traits into classes, and instantiate objects of these trait
classes in the classes that uses the trait. This instanti-
ation can be done hierarchically.
Every call of a trait method has to be updated to
call the method of the correct object (the instantiated
trait class). We search the syntax tree for every node
which contains a method call, and update the refer-
ence according to a table of references to trait objects.
A couple of problems raise in this process. To support
ICSOFT 2008 - International Conference on Software and Data Technologies
42