Jumbo Examples
Traits
This paper by Scharli, Ducasse, Nierstrasz,
and Black introduced the idea of traits, "composable units of behavior" encapsulating methods, but not states, that
describe behaviors that should be common across many classes. They are designed to reduce code duplication, being
especially useful in situations where the class hierarchy prevents using inheritance for code reuse.
One of the defining factors of traits is that they can be flattened; a class with added traits should behave exactly as
though the methods were written in the class itself. This clearly leads to a straightforward implementation in Jumbo.
Two main classes were used to implement traits in Jumbo.
The
TraitMethod class keeps track of each method that could
be added to a trait, what that method's name is, and what other functions that method requires.
New trait methods are defined by extending this class and defining the getCode function to
return the code of the method.
The
Trait class keeps a set of TraitMethods, and has functions to rename methods and compose
traits.
Renaming a method in a trait in Jumbo is a simple matter of finding the method in that trait
with the given name, and changing its name to match the new one. Composing traits is similarly
easy: unify the method sets of each trait, and annihilate methods with conflicting names (as
described in the paper).
Using a trait in a generated class in Jumbo requires calling the GetCode() function of the
Trait. At this point, the Trait will generate code for each of its methods, using the name
currently mapped to that method, and return a MonoList of Code containing all the methods
generated. MonoLists of Code are the datatype used in Jumbo to represent class bodies; the
list returned by the Trait can therefore be appended to the existing body of a class to be
generated. This necessitates that the class utilizing the trait define its body as a MonoList
of Code; the list of code from the trait cannot be spliced in later. For now, a
TraitUser class
has been defined that allows
method and state variable code to be added to a MonoList, to be used as the basis for a class
utilizing Traits.
One thing about the structure of Jumbo causes some issues in the implementation of traits. Jumbo does not allow
inspection of quoted code values. This is why the code for the methods of a trait is not generated until the getCode()
function is called; there would be no way to rename a method that had been already generated. The inability to inspect
quoted code also means that the only way to determine whether a class a particular trait is being plugged into meets
that trait's requirements is to either attempt to compile it and see if it produces errors, or to use a wrapper class
(similar to the Traits and TraitMethods) keeping track of what methods the class can provide to traits it utilizes. The
latter method, however, complicates the process of creating a trait-using class, and still has issues with determining
the methods provided to the class through inheritance; therefore, we have opted to allow the compiler to catch any
issues where a trait is used with an unmet requirement. Finally, our inability to determine what methods are already
defined in a class into which we are inserting trait code means that we cannot fulfill one of the specifications of
traits; namely, that they are overridden by methods defined in the class itself.
Download the
Jumbo Trait test code!