Skip to content
Apr 13 2010 / alecmce

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 Orange to the fruits vector, 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 the Vector), 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.

  • http://twitter.com/robpenner Robert Penner

    Great article. Small point: there are actually 4 Vector classes, for Object, Number (called “double”), int, and uint. I decompiled playerglobal.swc and posted the Vector source here:

    http://gist.github.com/365059

    • http://alecmce.com Alec McEachran

      Thanks. I’m certain that it’s my memory of the conversation that is at fault, rather than Nicolas’ explanation of what’s going on under the hood. I’m certain he did a similar thing to you.

      Thanks for the fact check! I’ll put a note into the body of the text as well.

  • http://noiseandheat.com/ mnem

    Good post, +1 vote :) It’d be very nice to have a feature like this.

    It may be worth having a look at Java generics too. It has some nice features such as wildcards and, more usefully, bounded wildcards. So, to have a function that can process a templated list of some specific family of objects, you could do:

    void doSomethingShapey(List shapes)

    Or mix the wildcards with solid types:

    void getAllTheStringyKeys(Map map)

    I haven’t seen any obvious way to do this in C#. It’d get around your fruit issue I think. Of course, there are limitations when using wildcards – for instance, I don’t think the compiler would allow you to add items to the collections, for the discussed reasons of type safety.

    I’d be quite happy if Adobe decided to drop AS3 and suddenly declare C# the language of Flash ;) Conceptually, it shouldn’t be hard. Of course, practically, it’s a bit of a bugger due to the way Flash movies are woven together, which is a shame.

    • http://alecmce.com Alec McEachran

      You should read through Ewan’s responses to my issue with Vector.<t> if you want to get around the fruit problem! It’s heavy going, but it looks like the covariance/contravariance approach is a good way to go.

  • Anonymous

    First off, the whole “.” thing between the type and the parameter is ridiculous. Get rid of it, Adobe. It’s a wasted character that serves no purpose whatsoever. ObjectPool looks so much better than ObjectPool.. A language should attempt to be clear, readable, and minimal and this violates all of that.

    And I do agree with @mnem, there should be wildcards like ObjectPool to allow multiple types. I created an issue in Adobe’s JIRA for generic type support more than a year ago, so if you’d like to vote on it, please jump on board :) https://bugs.adobe.com/jira/browse/FP-811

    We most certainly need generics/parameterized types/methods, as well as overloadable methods. I, like you, hope that Adobe will make the move and jump on board for this. Great article, by the way!

    • http://alecmce.com Alec McEachran

      Thanks for the feedback. I sympathise with your dislike of the rather pointless dot, but must disagree. There’s already a dot in Vector.. It is a much more heinous crime to break an existing API than it is to add a pointless and unnecessary dot. So, while as I say I sympathise and think it a bizarre syntactical decision, there it is and we’re stuck with it.

      • Anonymous

        It could always be made optional. That seems reasonable to me. That way, it doesn’t break existing code and leaves the option up to us. Just a thought :)

  • http://twitter.com/robpenner robpenner

    Great article. Small point: there are actually 4 Vector classes, for Object, Number (called “double”), int, and uint. I decompiled playerglobal.swc and posted the Vector source here:

    http://gist.github.com/365059

  • http://noiseandheat.com/ mnem

    Good post, +1 vote :) It'd be very nice to have a feature like this.

    It may be worth having a look at Java generics too. It has some nice features such as wildcards and, more usefully, bounded wildcards. So, to have a function that can process a templated list of some specific family of objects, you could do:

    void doSomethingShapey(List<? extends Shape> shapes)

    Or mix the wildcards with solid types:

    void getAllTheStringyKeys(Map<String, ?> map)

    I haven't seen any obvious way to do this in C#.

    I'd be quite happy if Adobe decided to drop AS3 and suddenly declare C# the language of Flash ;) Conceptually, it shouldn't be hard. Of course, practically, it's a bit of a bugger due to the way Flash movies are woven together, which is a shame.

  • http://alecmce.com alecmce

    Thanks. I'm certain that it's my memory of the conversation that is at fault, rather than Nicolas' explanation of what's going on under the hood. I'm certain he did a similar thing to you.

    Thanks for the fact check! I'll put a note into the body of the text as well.

  • rfkrocktk

    First off, the whole “.” thing between the type and the parameter is ridiculous. Get rid of it. It's a wasted character that serves no purpose whatsoever. ObjectPool<Robot> looks so much better than ObjectPool.<Robot>. A language should attempt to be clear, readable, and minimal and this violates all of that.

    And I do agree with @mnem, there should be wildcards like ObjectPool<? extends Robot> to allow multiple types. I created an issue in Adobe's JIRA for generic type support more than a year ago, so if you'd like to vote on it, please jump on board :) https://bugs.adobe.com/jira/browse/FP-811

    We most certainly need generics/parameterized types/methods, as well as overloadable methods. I, like you, hope that Adobe will make the move and jump on board for this. Great article, by the way!

  • http://alecmce.com alecmce

    Thanks for the feedback. I sympathise with your dislike of the rather pointless dot, but must disagree. There's already a dot in Vector.<T>. It is a much more heinous crime to break an existing API than it is to add a pointless and unnecessary dot. So, while as I say I sympathise and think it a bizarre syntactical decision, there it is and we're stuck with it.

  • rfkrocktk

    It could always be made optional. That seems reasonable to me. That way, it doesn't break existing code and leaves the option up to us. Just a thought :)

  • http://alecmce.com alecmce

    You should read through Ewan's responses to my issue with Vector.<T> if you want to get around the fruit problem! It's heavy going, but it looks like the covariance/contravariance approach is a good way to go.

  • http://1ndivisible.com Pedr

    Nicely put. I think I understand Generics at last.

  • http://1ndivisible.com Pedr

    Nicely put. I think I understand Generics at last.

  • Aan

    Adobe actually is spending a lot of time to improve the language and compiler. Soon everyone will be able to cross compile applications for the iPhone!

    …oh wait….

  • Aan

    Adobe actually is spending a lot of time to improve the language and compiler. Soon everyone will be able to cross compile applications for the iPhone!

    …oh wait….

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

  • Nicolas Cannasse

    Generics are indeed one of the features that every decent modern programming language should have, but that’s not the only reason to switch to haXe, which also have type inference, anonymous structures, enums, macros, inline functions, and much much more.Maybe I’m biased, but I don’t expect AS3 – which hasn’t changed a bit since it was released – to get these features anytime soon.During “transition time” you can use haXe and compile your code to AS3, or have haXe generate a SWC than use it from your existing AS3 code.

  • http://twitter.com/potapenko potapenko

  • http://twitter.com/potapenko potapenko

    For the author. You forgot about Realaxy ActionScript Editor. It has support for generics in AS3 as a language extension. 

    • http://alecmce.com Alec McEachran

      I published this on April 13, 2010. As of 22 August 2011 Realaxy Editor doesn’t have a debugger or profiler. I am happy to look at your application once it compares to the tools I currently use. (I would concentrate on these core features rather than language extensions if I were you.) The language extensions concept is a thorny one in any case, because it binds the code you write to your editor, which makes me deeply uncomfortable. Any code I write with your language extension is bound to your editor. A clever way to keep your community, but a very dangerous road to go down for teams of developers.

      • Anonymous

        You’re right, there is no debugger in Realaxy just yet. Frankly speaking, the debugger can wait. It is a matter of personal opinion, but I find a combination of a good logging and a test covering would be enough. So much so, that the debugger will be included in RASE approximately in the next 1.5-2 months (just after the release we’ll launch a version 1.1 with it). To return to what I was saying, Realaxy offers some practical tools for working with generics. As opposed to all specified solutions (I mean the future AS and HaXe), Realaxy can providing the most feasible way of using generics, doesn’t it?

        Concerning your attitude to the language extensions: I respect your opinion and concerns. 

        However, I may be permitted to take a dig at this evaluation: for me it feels like a fear of novelty. Maybe the approach of Jetbrains MPS (Meta Programming System) is too radical or the idea of meta-programming has not yet become a trend among the AS developers community. Until the meta-programming has not turned into a mass phenomenon, you can be afraid of using Realaxy in production. It’s OK, I reckon, to look at such ideas with a jaundiced eye.

        As for the “binding code to the editor”: this statement does not reflect the reality. You are always free to generate a pure AS3 code and continue to work with it just as you like.

        As for the comfort of writing code, I’m also disagreed with you and believe that the approach that came up with the guys from Jetbrains is a revolution in facilitating of writing a code. Realaxy Editor is developed in Realaxy Editor. We compose its code in MPS-way, we do it every day. Everybody who has ever tried this way finds it extremely comfortable and productive.

        As for the April 2010 – yes, more than a year have passed away, we’ve added lots of features since that. A new Collections language http://goo.gl/T9oxm, operators overloading, traits support http://goo.gl/Ii6xY, tuples, assert are added. The code editor is more smart now. A propos, we’ve get a significant performance boost and beta-testers confirm, that Realaxy is for the moment one of the quickest AS-oriented code editors. If we will compare the editors which have a similar functionality with Realaxy (refactoring, type system checks, etc) – it is the fastest. So we’ve really improved RASE since April 2010. (This is a reply to your message, “I saw you years ago and nothing has changed – so, it is not).

        We plan to launch a release next month (September 2011) and look forward to your interest and approval. Sorry for lengthy comment :)

        P.S. Try Realaxy for testing. Tests coverage. This is a good reason to use the power of language extensions and the ability to write a code which is closer to a human language. The test phrase should be compact and laconic. For example, I use the overloaded operator “equals” (to compare some different classes), assertation language, collections, and I find such an approach to testing to be a very efficient one. Look at this test coverage http://goo.gl/T9oxm. I think that the testing of more complicated systems using the DLSs will look even more advantageous.

      • Anonymous

        You’re right, there is no debugger in Realaxy just yet. Frankly speaking, the debugger can wait. It is a matter of personal opinion, but I find a combination of a good logging and a test covering would be enough. So much so, that the debugger will be included in RASE approximately in the next 1.5-2 months (just after the release we’ll launch a version 1.1 with it). To return to what I was saying, Realaxy offers some practical tools for working with generics. As opposed to all specified solutions (I mean the future AS and HaXe), Realaxy can providing the most feasible way of using generics, doesn’t it?

        Concerning your attitude to the language extensions: I respect your opinion and concerns. 

        However, I may be permitted to take a dig at this evaluation: for me it feels like a fear of novelty. Maybe the approach of Jetbrains MPS (Meta Programming System) is too radical or the idea of meta-programming has not yet become a trend among the AS developers community. Until the meta-programming has not turned into a mass phenomenon, you can be afraid of using Realaxy in production. It’s OK, I reckon, to look at such ideas with a jaundiced eye.

        As for the “binding code to the editor”: this statement does not reflect the reality. You are always free to generate a pure AS3 code and continue to work with it just as you like.

        As for the comfort of writing code, I’m also disagreed with you and believe that the approach that came up with the guys from Jetbrains is a revolution in facilitating of writing a code. Realaxy Editor is developed in Realaxy Editor. We compose its code in MPS-way, we do it every day. Everybody who has ever tried this way finds it extremely comfortable and productive.

        As for the April 2010 – yes, more than a year have passed away, we’ve added lots of features since that. A new Collections language http://goo.gl/T9oxm, operators overloading, traits support http://goo.gl/Ii6xY, tuples, assert are added. The code editor is more smart now. A propos, we’ve get a significant performance boost and beta-testers confirm, that Realaxy is for the moment one of the quickest AS-oriented code editors. If we will compare the editors which have a similar functionality with Realaxy (refactoring, type system checks, etc) – it is the fastest. So we’ve really improved RASE since April 2010. (This is a reply to your message, “I saw you years ago and nothing has changed – so, it is not).

        We plan to launch a release next month (September 2011) and look forward to your interest and approval. Sorry for lengthy comment :)

        P.S. Try Realaxy for testing. Tests coverage. This is a good reason to use the power of language extensions and the ability to write a code which is closer to a human language. The test phrase should be compact and laconic. For example, I use the overloaded operator “equals” (to compare some different classes), assertation language, collections, and I find such an approach to testing to be a very efficient one. Look at this test coverage http://goo.gl/T9oxm. I think that the testing of more complicated systems using the DLSs will look even more advantageous.