Important note: The traits prototype described here is out of date. A new, cleaner and more stable implementation is available on SqueakMap and can be loaded in Squeak 3.7 or later.
This document gives some important information about the traits prototype implementation in Squeak.
1) The traits model
2) About this prototype implementation
3) Overview of the implementation
4) Limitations -- Why is there no changeset yet?
5) Tutorial
6) Download and Wiki page
The basic ideas and concept of Traits is described by several papers that can be found at on the research page about traits. The concept paper introducing traits has been accepted to ECOOP 2003. A preliminary version is available as a tech report.
Furthermore, there is a tech report that describes the practical experience of applying traits in order to refactor the Smalltalk collection hierarchy. This paper should give a good overview of how traits can be used in practice.
Just about a year ago, we started to work on the concept of traits, and because we are convinced that practical experience is a crucial part of any kind of language design, I started to implement a prototype version as soon as we had a first rough idea of the model. As expected, working with the prototype gave us valuable insights for the further development of the traits model, and as a consequence, the traits prototype evolved and changed a lot. However, the purpose of the implementation remained the same: we wanted to have a prototype that allows us to play with the main features of the model.
It has always been the idea that traits should at one point be available for Squeak and potentially also for other Smalltalks. (The VisualWorks team actually plans to implement a first prototype version sometime this year). Therefore, I planned to build a new version of traits that is essentially a refactored version of our prototype with a clean design that addresses the fact that the current traits model is quite different from the one we had initially implemented. This version should then be available as a clean changeset on SqueakMap.
Unfortunately, I just haven't found enough time for doing this and after a while I realized that I need to change my plan: instead of waiting until I have the time for doing a clean version, I just fixed the most common bugs in my protpotype and then put it out. Like that, interested people can play with it, and if someone gets inspired and is interested in transforming this prototype or a part of it into a clean version, I would be more than happy to collaborate and share all my ideas and insights. So, just let me know!
In the meantime, we are going to further develop an extended version of the traits model, and we are of course also implementing it. This new implementation has two purposes: On one hand, it will serve as a research vehicle for the extended model, but at the same time, we also want to make sure that it can be used as s stable version for the current model. This means that we are planning to generate a stable traits changeset based on this new version.
The traits implementation can be separated into kernel and user interface.
The traits kernel can again be separated into two parts. On one hand, there is the part that is necessary to represent a trait, to allow trait composition and to make sure that the trait methods are integrated into the classes in a semantically correct way. On the other hand, there are some extension that allow realtime reasoning about the code. This part is basically independent of traits and would already be a valuable extension of a regular Smalltalk system. It provides some of the benefits of strongly typed languages without additional overhead for the programmer. For example, it helps identifing spelling mistakes in methods sends and helps finding abstract classes that should actually be concrete.
Whereas this reasoning is pretty useful in a regular Smalltalk system, it is nearly essential in a system with traits. It has a big impact on the practical usability because it is a key for helping a programmer understand how the different aspects of a class/trait are related to each other.
In order to represent traits, there are classes TTrait and TMetaTrait,
which are essentially subclasses of ClassDescription. (It may seem that it
would
be better to make them subclasses of Behavior, but I decided against it because
I wanted to reuse things such as the class organization). Because I didn't
want to mess with ClassDescription, I also created a new subcass TClassDescription,
which serves as the new superclass for classes that are able to use traits.
This part allows realtime reasoning about the code, which means that it provides the programmer with information that is updated system-wide whenever a method is changed. The information includes things such as required methods (methods that are required in a class but are not yet implemented), unbound super-calls (super calls that refer to an inexistent method), etc. In addition, there are trait specific information. For example, information that shows how two traits are glued together and indicates conflicting methods.
Most of the code necessary for this reasoning is integrated into the class
TClassDescription and its subclasses. Since changing a method
in a class "high in the hierarchy" may have impact on many classes
throughout the system, caching
of some data
is necessary in order to do the required analysis and updates in real-time.
Although the current prototype imlementation uses such a caching strategy,
it still
can
be a bit slow for certain changes in classes such as Object.
Unfortunately, I didn't have the time for further optimizations and I also
haven't finished
the implementation of "smart lazy update mechnism" yet.
The user interface mainly consists of the "TraitsBrowser", which is an extension of the regular Smalltalk Browser. The main differences are the fact that the TraitsBrowser has a modified class pane that shows how the selected class is composed from traits and that there is an extended protocol pane that contains "virtual categories". These virtual categories contain selectors that are important for the understanding of how the selected class (or trait) is composed. Furthermore, all panes now use colors to differentiate traits from classes, indicate abstract classes, differentiate between required, provided and conflicting methods, etc.
There are several reasons why there is no changeset for traits yet. The meain reason is that I just haven't found the time yet to create a version that is "finished enough" to be of great value for "real programming" (e.g., there is still no file-in/file-out for classes containing traits).
Another
reason is that filing in traits requires recompilation of the whole system.
This is because we need to add some instance variables
to ClassDescription and because we need to generate some
data to fill the caches for the incremental reasoning. Unfortunately, the
kernel (resp. the ClassBuilder) of Squeak is broken for at least half of
the (inofficial)
versions
since Squeak
3.2, and it is also broken for the latest version of Squeak 3.4 (state January
31). Thus, it would not
be possible to load a traits changeset into such an image even if it
would
exist.
As you can see in Section 4.3, there are still many limitations of the current Traits prototype. However, it is not that we wouldn't know how to implement/solve them, it is just that at the moment, we don't have the time to do all the required work. However, if someone is inspired by this prototype and is interested in bringing all or parts of it to a state where it can actually be used in a productive way, I would be more than happy to cooporate and share the knowledge I have gained during my work on this. So, just let me know!
As I already said above, we are also planning to do a stable implementation of traits that will be available as a changeset on SqueakMap. However, since we want to make sure that this stable version can also be used as the implementation basis for the extended traits model we are currently working on, it probably takes some time until we are there...
The following list contains the major limitations of the current trait prototype implementation. As I pointed out above, I just didn't have the time to do work on them yet. So, if someone is interested in tackeling one of these issues, please let me know.
This is actually not a real tutorial, but just a few screen shots showing the different features of the TraitsBrowser. The example code is the same as discussed in the concept paper.
1) The Traits Browser. This is the Traits Browser with now class selected.


3) Generating a trait from a class. When generating a trait from an existing class, the system automatically replaces instance variable accesses through accessor methods. Note that you can specify whether also method in superclasses should be included.

4) Creating a class that uses a trait. Creating
a class MyPoint that uses the trait TPoint.

5) A class that uses a trait. The programmer can choose whether he wants to see all the methods available in a class, only the methods that are defined within the class itself, or the methods that are provided by a trait.

6) A class that uses multiple traits and exclusions. The
class EColoredCircle is built from 4 traits. The composition clause
specifies that the methods #= and #hash are excluded
from the trait TEColor.

7) Selectors and methods. The button row above the text pane indicates the status and the different implementations for the selected selector.
TECircle)-super-)TEColor)Note that left-clicking on any of these buttons allows to see the source code of the method implemented in the respective trait or class.

8) Selectors and methods II. The button row above the text pane indicates the status and the different implementations for the selected selector.
TECircle)TEDrawing)
9) Virtual categories and color coded selectors. Virtual categories ensure much easier understanding of a composition.
-requires-: This category contains all the selectors
that are required by the currently selected trait/class.-supplies-: This category contains all the selectors of the currently selected
trait/class that satisfy a requirement of another trait/class that is involved
in the composition.-overrides-: This category contains all the selectors of the currently
selected trait/class that override a method of another trait/class that is
involved in the composition.-overridden-: This category contains all the selectors of the currently
selected trait/class that are overridden by a method of another trait/class.-conflicts-: This category contains all the selectors of
the currently selected trait/class that are subject to a conflict.The color codings of the selectors are related to this virtual categories:

10) Menus associated with the button row. Right-clicking on a button in the button row opens a context menu that provides convenient short-cuts. In the figure shown below, we can for example remove the exclusion of a selector without having to manually edit the composition clause. Other menu features include:

11) Navigating to subtraits. Unfortunately,
the current version of the TraitsBrowser does not contain a tree widget that
allows easy inspection of deeply nested traits. In the context
of EColoredCircle it is for example not possible to see that the trait EColor
actually contains several subtraits. In order to compensate a little bit for
this limitation, we can jump to the definition of a subtrait by double-clicking
on it. Then, we can use the back-button (<-) to go back to
the previous context.
The following figure shows the state after double-clicking on
the subtrait TECircle in the previous figure.
