Adding Multiple Inheritance to AS3 with Traits and Realaxy Editor
In this post you'll learn about a language extension called Traits, a feature of a new Beta of RASE, a smart and modern IDE for Adobe Flash based on Jetbrains MPS. Traits will allow you to use multiple inheritance in your projects, so a class can effectively extend two other classes.
The sample project was created with ActionScript 3.0 with Traits language extension using Realaxy ActionScript Editor (RASE). If you want to do it the same way, RASE can be downloaded here (if you are new to RASE please follow the Beginners guide here)
Why Use Multiple Inheritance?
ActionScript is a modern object-oriented language. At the moment, actual OOP defenition and interpreting assume that multiple inheritance is a vicious practice. Thus, AS itself does not permit multiple inheritance, and only the using of interfaces provides an alternative. It's all well and good, no need to argue.
However, sometimes it seems unbearable. It happens that owing to this missing feature we make our code too sophisticated or even probably messy.
For instance, we have a class
Creature, which already extends
Sprite. We want to teach it how to speak. "A proper OOP" imposes us to make a composition. So we need to:
- Create an
- Add a
- Implement this interface with a
Creatureclass should be inherited from
- Then add a delegate to the
peakmethod would redirect calling of
speak()to the delegate.
- Well, it's done.
Let's imagine we have multiple inheritance. Then we make a
Speaker class, inheriting our
Creature class from the
Speaker. That's all, folks.
Then, imagine our Creature should be able to do a lot things: to walk, to move arms and legs, to eat, to smile, to cry. Maybe also to fly. You never know what kind of requirements could become a part of the spec. As a result, we gain hundreds and thousands of lines of a "proper" OOP code, which is so redundant and verbose, that understanding its real purpose would be difficult even to its author.
We, skilled Flashers, understand that the situation described is purely artificial. Who would create a pack of interfaces for every aspect of behavior? Even if those would be applicable not only for
Creature. Indeed, the real code would look different, not so pretty and learnedly, but closer to the real world - that is to say, simpler.
So it turns out that the best intentions of ECMAScript's (and, later, ActionScript's) designers to create a modern and correct OOP language accommodate badly for our everyday work.
Enough complaining! We have a tool to fix it. RASE. Realaxy ActionScript Editor. This solution is Traits, an AS3 language extension.
Let's proceed to action.
First, create a new project with
testTraits module containing main-class
Enter the project details as shown here, and click Next:
Create a new class called
Creature, in the package
This code should be created:
Import a traits language by pressing Ctrl+L (or Command+L).
Create a Speak interface with a single "speak" method.
The lower part of the window has two tabs, "Interface" and "Trait".
Select the "Trait" tab (colored with gray) and click on the empty editors field. A dialog box appears, offering us to create a new trait.
After "OK" a default implementation is created by editor. Note how this is now
trait Speak rather than
Add a body to the "
speak" method: just trace "Hello!" to the console.
In the Creature class add a "Speak" interface to "implements".
The editor added an "i" to the right of the interface name. It means that the interface has a default implementation -- it has trait behavior.
RASE recognizes such behavior and does not highlight any error when methods are added to class.
That's it! Our
Creature can talk now! Add a call of method
speak() to a class constructor to prove it.
Edit the run-configuration.
You'll see this dialog:
Press the "+" button to add a new Configuration, and select ActionScript.
Enter the details as shown here:
(This way we can be sure we'll see the trace.)
Run the compiled SWF. A "Hello!" message appears in the console.
Here's what we obtain:
- Code of interface and of implementation are bound up with navigation tools and bookmarks in editor.
- Code is now well-organized. Every implementation has a name: an interface name + "
- Boost of the usability. In a class that uses this behavior, we only add our interface to the
- Keeping apples and oranges separate. Code of
Creatureclass is not "littered" with excessive entities. We've just ordered the Creature to talk.
As a result, we have behavior that is really like multiple inheritance but stands on "proper and correct" OOP recommendations.
Let's see how it works, by looking at the code we're actually generating.
Click "Build->Generate (obsolete)->Generate Text from Current Model". The newly generated code of the
Creature class appears in the Output window.
The code demonstrated above implements a classical composition. The trait language extension hides redundant entities and organizes relationships between code artifacts. In fact, we operate a "pure" OOP code.
Now we see a new fast and easy way to teach our
Creature how to do everything. The main thing is the behavior: we apply the same ground rules to another classes.
Let's do it in 5 minutes.
Add some new traits -- one for each limb -- just as we did before:
The Creature class gets now a lot of new skills, but its code remains easily-readable and clean. Without the Traits language extension it would be completely different:
It's time to say goodbye. I'm waiting for your questions, suggestions and comments.
Remember, if RASE is new to you, please read the "Beginners Guide".