Why we need Generics in AS3
Introduction
Almost not a day goes by that I write some code destined for a library and wish that Adobe had implemented generics for AS3. Generics is the ability to specify a type that will be used within a class without explicitly defining the type. If you are developer that has started coding for player 10, then you’re probably familiar with the Vector implementation. This is currently the only place that generics exists in AS3, and it sticks out like a sore thumb. Generics are useful for one main reason: it is easier to write code that can be massively re-used if you can use generics. More code reuse means less code. Less code means smaller applications, faster code, and more time for better features. There are few down-sides to generics.
What Are Generics?
Object pooling is something I need to do reasonably often. I would like to be able to create an interface that allows me to describe some common features of an IObjectPoolable item, such as a reset() method that could be called to clear out any data particular to an ‘instance’ of the object. I would then like to be able to specify an ObjectPool class and specify which kind of IObjectPoolable type it is pooling. Then, when I call ObjectPool.consume(), I don’t have to type-cast the object it gives me, because the compiler knows what kind of object it is. It knows, because I defined it when I constructed the ObjectPool.
The code for such a class might look something like this:
class ObjectPool.<T:IObjectPoolable>
{
private var _pool:Vector.<T>;
private var _index:uint;
public function ObjectPool.<T>()
{
_pool = new Vector.<T>();
_index = 0;
}
public function alloc(count:uint):void
{
for (var i:uint = 0; i < count; i++)
_pool.push(new T());
}
public function dealloc(count:uint = 0):void
{
if (!count)
count = _pool.length;
_pool.length -= count;
}
public function consume():T
{
return _pool[_index++];
}
public function release(object:T):void
{
var i:uint = _pool.indexOf(object);
if (i == -1)
throw new Error("You cannot release an object into a pool that it does not come from");
object.reset();
_pool[i] = _pool[index];
_pool[--index] = object;
}
}
T in the above example stands for the type which the ObjectPool pools. Of course, I can’t test this code so there may be logical errors, but hopefully you see where I’m going with this.
Perhaps you think that I could do the same thing without generics, by adding run-time checks into my code. That will make the code slower than it should be, and in order to check whether it works I’ll have to run it because errors will only arise at run-time. Compile-time checking is better than run-time checking.
Perhaps if I have Robot objects and Donkey objects I could create two object-pool classes: a RobotObjectPool and a DonkyObjectPool class? That implies that for each IObjectPoolable object that I create I will also need to create a new object pooling class. That’s bad in so many ways. It means less code reuse (in fact, I may end up copying-and-pasting code into classes!), the application’s code weight will increase (fewer bangs for your bytes), there are more places where errors could creep into my code, and I have to spend all that extra time creating all those extra classes.
A Related Limitation of interface
You may have noticed that in the alloc method above I am constructing the type using new T(). Within the interface IObjectPoolable I have no way of enforcing that the constructor requires no arguments. I should have, either by being able to specify:
public interface IObjectPoolable
{
function IObjectPoolable();
}
or
public interface IObjectPoolable
{
function new();
}
or something like C#, in the ObjectPool class itself, specifying new() to indicate a parameterless constructor:
class ObjectPool.<T:(IObjectPoolable,new())>
Note also that to illustrate generics I chose an example in which I wanted to be able to restrict T to a particular set of types, using <T:IObjectPoolable>. This is elegantly done in C#, it should be done in ActionScript too.
Vector.<T>
Currently one implementation of generics exists, for Vector.<T>. On the face of it, it is extremely perplexing why generics have been implemented only for Vector, but there are practical reasons why Adobe can’t simply roll generics out. The Vector.<T> was implemented because of a realisation that iterating over Array represented a specific performance overhead that Adobe could do something about.
During his recent visit to the Flash Gaming Summit, Nicolas Cannasse explained to me that Vector is a hack comprising three classes under the hood. In fact, Adobe engineers have created Vector.<int>, Vector.<Object> and (I think – though this one is hazy) Vector.<Number>.
UPDATE: Robert Penner informs me that I remember this incorrectly. There are in fact four Vector implementations. Follow the link to the comment below for more details.
The two numerical implementations are designed to give specific speed improvements when iterating over collections of numbers. The Vector.<Object> implementation is the catch-all for all other type. However, Adobe has clearly done the work necessary for compile-time checking that the type being passed into the Vector.<Object> is preserved throughout the code.
Adobe then has done a lot of work towards implementing generics, but the Vector implementation was a specific workaround. As we are probably all aware, there’s a huge difference between a workaround and a truly flexible feature.
haXe
If I like generics, why not start using haXe, since haXe has generics already built in?
There are a few reasons why I’m reluctant to go down the haXe road at the moment.
- Firstly, there’s code I write for myself, and code I write for my work. The work code has to be AS3. I find it harder writing in two dialects of the same fundamental language than I do writing to completely different languages.
- Then, there’s the prospect of having to rewrite almost everything in my library. If I move back into a self-employed mode in the future, then there is little doubt that I’ll adopt haXe, but if I’m doing this in spare time, it is a daunting task.
- Then there’s the lack of haXe support in FDT. This is going to change soon, but until I can write haXe without having to give up the tools that I love to work with, that represents a significant barrier to entry.
In many ways, haXe blazes far ahead of AS3 for these sorts of language requirements. It is frustrating that AS3 lags behind haXe when AS3 has a team and corporation behind it, while haXe has a handful of extremely talented people. If AS3 can’t iterate closer to haXe and soon, there may be no option but to go down the haXe road in the next few months.
Issues
With generics there are certain complications that should be addressed. The most subtle of these is something I highlighted in my article The Problem with Vector<T>. I incorrectly argued that the following should be ok:
public interface Fruit; public class Apple implements Fruit; var fruits:Vector.<Fruit>; var apples:Vector.<Apple> = new Vector.<Apple>(); fruits = apples;
The problem was really that perhaps I had a makeSmoothie(Vector.<Fruit>) method somewhere that expected Vector.<Fruit>, I would have to construct a new Vector.<Fruit> and pass in each member from Vector.<Apple> before then passing that newly constructed object into makeSmoothie. This seemed like an expensive overhead to me.
My brother Ewan pointed out that this is not straightforward. He wrote three articles on this:
- the first exploring the problem of trying to add an
Orangeto thefruitsvector, and the consequences surrounding that; - the second discussing how C# 4.0 has the potential functionality to get around that problem, by defining two generic types, so that perhaps a class could be defined as
Vector.<Fruit, Apple>, where essentially the first type is the exposed type (what you get if you reference an index in theVector), while the second type is the required type (what type is allowable to be set as a reference for an index). - and finally an article which explains the concepts behind the C# 4.0 implementation from it’s core concepts of covariance and contravariance.
Conclusions
This stuff it extremely complex; it is a can of worms that if AS3 did implement generics it would have to consider and take seriously. Though designers complained about AS3′s complexity over AS2, I doubt anyone can seriously argue that AS3 wasn’t a huge step forward in terms of potential and power. ActionScript is now grown up, but it is still young and it still has lots to learn. Now Adobe are creating tools that allows designers to produce many of the more simple functionalities in Flash without having to touch code. That’s great in my opinion, it allows people like me to spend more time developing more interesting stuff that can’t be tied down to a drop-down menu in Flash CS5. I have a good toolset for that right now, but I want and need more tools. While the IDE and player evolve, the language is standing still.
The ActionScript developer community is a huge asset for Adobe. We are the heart of the Flash Platform. Right now, it’s much stronger than most people give it credit. For example, Microsoft’s new KIN website was developed in Flash, not Silverlight! This is surely because the UI developer talent still works in ActionScript for Flash, not in C# for Silverlight.
However, this can change quickly. The Flash Platform is now clearly challenged, from Apple, HTML5 and Silverlight. Many developers are considering migrating to other languages and platforms. Many have retooled to work on Objective-C, Android, and HTML5. Many work in multiple languages. The danger for Adobe is that gradually more and more people drift away from using ActionScript as their day-to-day language of choice. If people move elsewhere and the quality of Flash content starts to wane, Adobe’s power-base dissolves with it.
ActionScript needs to evolve. It could do worse than evolving to support generics.



Pingback: An AS3 Left leaning Red Black Tree | Nicola Bortignon