Function Overloading in AS3

Why doesn't AS3 have function overloading

If there is anything I hate more than when actionscript doesn't do something I wish it would, it is when people complain about something they wish it would do. Sure, it would be nice if it incorporated every programming concept ever but that just isn't going to happen. In fact, this point is the same for every language out there. It sure would be nice if they all did everything but then there would only be syntacticular differences and that would be silly. Anyway, actionscript does not natively offer function overloading, and I've heard and/or read people complain about that from time to time.

Roll your own

Usually the reason you wish a solution existed natively is because you've used it before and you'd like to have the same ease writing the code. At least, if we follow the premise of not pre-optimizing code. So, if a language doesn't have that construct what do you do? Either find an alternate or roll your own. Today we are going to roll our own method for overloading functions in AS3 to allow for some of the benifits of native function overloading.

This isn't my idea

I have to admit, this isn't my idea. Back in the days of AS2, there was one library that did a lot of rolling its own solutions to constructs actionscript didn't provide. That library was as2lib by Simon Wacker and Martin Heidegger. I remember just reading the as2lib source code to learn different ways of doing thing. They had a solution for function overloading that I used as a basis for the AS3 code. I figured, AS3 had better reflection and introspection (as2lib had libraries for that as well) than AS2 so this should be fairly easy. In some ways it was and in some was it wasn't. That's a good thing because I learned a few things along the way.

Enough typing, where's the code

The code I wrote to allow this functionality is available at github. Usual rules apply, this code is just a proof of concept, for educational purposes only. Though I've written some tests, I make no guarantees.

Sample Usage

Sample usage is available in the Main.as file on github but I'll provide you with a taste here.

private function aFunction(... args):* {
    const overloader:Overloader = new Overloader();
    overloader.addHandler([String, Number], onStringNumber);
    overloader.addHandler([String], onString);
    overloader.addHandler([Number], onNumber);
    overloader.addHandler([int], onInt);
    overloader.addHandler([uint], onUint);
    overloader.addHandler([Boolean], onBoolean);
    return overloader.process(args);
}

private function onInt(value:int):void {
    trace("We got int: " + value);
}

private function onUint(value:uint):void {
    trace("We got uint: " + value);
}

private function onBoolean(value:Boolean):void {
    trace("We got Boolean: " + value);
}

private function onNumber(num:Number):void {
    trace("We got number: " + num);
}

private function onString(str:String):void {
    trace("We got string: " + str);
}

private function onStringNumber(str:String, num:Number):void {
    trace("We got string, number: " + str + ", " + num);
}

// then to use the overloaded function
public funciton Main(){
    aFunction("Hello World", 13); // output: We got string, number: Hello World, 13
    aFunction(1 == 0); // output: We got Boolean: false
    aFunction(13); // output: We got uint: 13
    aFunction("Goodbye"); // output: We got string: Goodbye
}

A couple notes and gotchas that you might be wondering about as you look at this code.

  • Numerical arguments are automatically converted to any numerical class asked for, as long as the value can be of that type.

    • For this reason I made it test numerical explicitness in the following order: uint before int and int before Number.

      • Therefore if their are two matching functions due to numerical parameters a method using uint will be considered more explicit than a method using int or number.
    • You can't force a numerical type. I tried several methods and none worked.
  • If your overloaded function returns void you will need it to return * so it will compile without error.
    • EDIT: not true, just don't use a return statement
  • Because AS3 uses method closures most of the time, instead of anonymous functions, you usually don't have to worry about function scope. This is mostly a good thing. Watch out if you do use an anonymous function though. It will most likely work correct but there are a few ways it could fool you.
  • I wanted to do introspection on the method signatures so you didn't have to send in the values but, alas, method signatures do not seem to be available via reflection. From what I could figure out from studying the Tamarin code, they are part of the functions Trait object which isn't available from actionscript (and may go away in the future according to the documentation). This means you have to put them in as Arrays.

Not True Overloading

Okay, so this isn't true overloading but it gets us a little of the way there. The only solutions available online use the ellipsis (...) method but you still have to write the boilerplate logic to provide type checking. Also, what happens if there is no match? With my code you at least get an error telling you what went wrong. It isn't compile time but it can help with debugging.

Also, look at what this solution actually provides. It doesn't have to be used for function overloading. It could be used anywhere you want to handle differing types of data passed in as arguments. I could envision this helping to trim down some nasty if and/or switch statements. Take a look and see what it could do for you.

Conclusion

I find the Function class and Function objects fascinating in actionscript. Back when I dug into the different types of Delegate classes for AS2 (I actually made a similar one for AS3 at one time) I learned a lot about the language as a whole. Scope used to be the bane of my existence and then I finally understood it. Scope may not be an issue anymore in AS3 but there is still quite a bit to learned about the language from studying Function objects. The very fact that a Function is an object that can be passed around in actionscript is a very nice thing. Not all languages allow that type of functionality. I guess if you are using those, you'll have to roll your own function passing solution.

Under the mask but I didn't ask - Flash Friday

Masks in the flash IDE are an interesting thing. You may have noticed that masks created in the IDE are not found in the normal "mask" property found on a movieclip. This is because it isn't a normal mask. The mask is working on a layer instead of on a single DisplayObject. This little quirk causes some interesting behavior that you may never have noticed before. If you have a MovieClip with a mask as a top layer of the timeline there is some strange behavior when you addChild to that MovieClip. The added content gets placed under the mask. Wait! What? The added content gets placed under the mask. You may not have noticed this behavior in the past because you may never have done it, you may not have your item cut off by the mask or you just might not have been able to figure out why you couldn't see your item. However, it is happening. [ad#Google Adsense] Another twist on this phenomenon is that if the mask isn't the top layer but your remove the items that are on the top layer then add a DisplayObject. Well, in that scenario your new DisplayObject is also placed under this "Layer Mask". I found this out today when I had a top layer above a mask that was a TextField. For a localization project I'm working on I had to wrap the field in a wrapper class that then gets added back where the textfield was. I was trying to figure out why the textfield was now appearing like it was under the mask. The answer...because it now was.

So how did I deal with this? How can you deal with this if you find it happening? First off, it might be an easy thing to just restructure your timeline so the mask isn't on top. If that isn't possible, the hack easy fix is to add a blank MovieClip symbol to the layer above the mask layer. That is what I did for this asset and all is well.

I haven't extensively tested this but my guess is the quirk may exist if you add something to any layer right above a "Layer Mask" it will placed under the mask. Is this something you have experienced? How have you worked around it? Have you used it for any type of effect?

I don't believe you really want to count on this behavior for anything as I don't believe I've seen it documented anywhere. Someone at Adobe might read my blog :) and decide this isn't appropriate behavior they might fix it in Flash Player 20 or something.

Flash Friday - Version Control

When I first started my Flash Friday posts I wanted to write about the whole flash ecosystem. At the time I thought about Flash, Actionscript, Flex, Flex/FlashBuilder and a few other tools. Recently, I have realized that the ecosystem is much larger than just flash. For people to truly be well rounded flash and actionscript developers who make every other flash and actionscript developer look good its important to know about these non-flash things. One of the most important things to any developer is version control. On the surface, version control seems simple enough. Save files in a way that allows me to go back in time if I make a mistake or forgot what I did in the past. Many people, a past version of myself included, think that's all there is to version control and thus us backup folders or file naming conventions to achieve this goal. I am writing this article because version control is way more than just this and definitely more important. For those who really master it you can actually save yourself quite a bit of time.

Why learn version control

If version control is more than backing up files what is it? I'm glad you asked. Version control is a way to safely and elegantly work with multiple people on a project. The multiple people include people in the same office or people on the other side of the world. It also includes the multiple yous that you wish you could create so that you could finish that cool new feature but you just can't take the time to hunker down and get it done all at once.

Version control is and/or allows:

  • Saving a history of your work as it evolves
  • Keeping track of who did what
  • Trying things out that you might throw away
    • Without breaking working code
    • Keeping a history of that as well
  • Working on a file without worrying if somebody else is
  • Taking someone else's work in a different direction ( forking )

What should you learn

  • SVN - The most popular centralized version control system
    • Lots of great tools makes it easier to include artists in the version control system
  • GIT - A very popular up and coming distrubuted version control system
  • Branching and Merging
    • Become a master at this for whichever version control systems you learn and it will make your professional life much simpler.

Tools

  • Subclipse - a great eclipse SVN plugin you can use with Flashbuilder or FDT
  • EGit - a similar eclipse plugin for Git
  • TortoiseSVN/TortoiseGit  - two great sell extensions for version control in Windows explorer.
  • GitHub - If you are working with Git this is a great place to start putting your code. Lots of straightforward how-tos
  • Books - I've found the following two books to be extremely helpful in learning SVN and Git

 

Final Notes

I mentioned SVN and GIT because they are currently in such wide use. However, version control concepts can be learned from any version control system. If your company or project is using something else, such as CVS or Mercurial, learn it and master as much of it as you can. I can't stress enough how important it is to master branching and merging. Get good at this and task switching will be much easier so you'll be able to working on many projects at once.

What are your thoughts on version control? What problems have you had? What successes have you had?

Flash Friday - A Simple List

The structure of a simple listA few people who've worked with me in a programming job may have heard me talk about how a custom list should be done. For performance reasons you don't want to recreate the visual "cell" n-times. That could lead to all sorts of unforeseen problems. Instead you want only enough cells to be visual during scrolling and as you scroll through the list just bring the "cells" round to the other side. One of the people I work with, Alec McEachran, wrote a blog post  on just this topic. It is entitled "A Simple List" and I'll let you read his article and code on the subject. What is interesting about his code  for a list is he does a great job keeping the list class very simple. It keeps to a pretty narrow responsibility. He's quite good at solutions with well defined class responsibilities.

In our current project, Monster Galaxy, we have used this code in a few places. It has been modified for our purposes but at the base level described in his article the code makes custom list designs easy to implement.

Alec is a very intelligent programmer and has some other great articles on his blog. If you like what you read there you might also like to follow him on twitter (@alecmce). Of course, his twitter feed carries a lot more of his opinions and personality. It's quite fun though, I promise ;)

Of course, I have a blog as well which you are reading now and thank you for that. If you haven't done so already, follow me on twitter( @diacre ) to find out about new blog posts as well as my opinions and personality ( which you may or may not find as colorful as Alec's ). Please let me know in the comments what you think of Alec's list class. If you have a different solution that you like I'd love to hear that as well. Until next time...au revoir.

 

Flash Friday Refactored - IS_IN

A while back I wrote a proof of concept isIn functionality injector that seemed to work fairly decently. I even wrote some tests for it that it passed with flying colors. Being a proof of concept I never really used it and never ran into the danger of using that functionality. Recently I downloaded the trial for FDT and since it doesn't have the same type of FlexUnit integration that FlashBuilder 4 has I had to get my tests working differently. When I got the tests up an running my tests for the isIn functionality blew up in spectacular fashion. They didn't just fail, the took the whole unit test display down with them. This was the same class and tests that passed cleanly before. What happened?

It turns out messing with the prototype of Object to solve a problem is like fighting fire with a nuclear explosion. It will probably work but cause serious problems throughout the system. So, following the test driven development methodology of red, green, refactor I saw that it was a time for a refactor. Well that and it was now a red test that I wanted to make green.

I came up with a solution that I think is better. It is more flexible than before, since you can select the class you want to add the functionality to. Even better, you can remove the functionality after you add it. Since I've begun to move my code over to GitHub you can find the new code over at https://github.com/darylducharme/Ducharme-Media-Code/tree/master/src/cc/ducharme/utils. The new test class is available at https://github.com/darylducharme/Ducharme-Media-Code/blob/master/test-src/utils/IsInTests.as

You may notice that the last test - dictionaryEnumerationTest()  at this time - is new. This is the test that checks the problem that I found that was not being tested before. If you are writing tests and find a hole in your tests later, it is always recommended to add new tests to keep you from having the same problem in the future.

Hopefully, someone out there can learn from my mistakes on this occasion. Also, the new isIn class and its static functions are a whole lot more useful than what I had written before. Perhaps someone out there can put it to good use.  What do you think?

Flash Friday - Robotlegs Context

A few weeks back I wrote an article saying that I was just starting to work with AS3 Signals and the Robotlegs framework at my new job. Since then I have written a post about AS3 Signals and now it is time to write about Robotlegs. Since there is so much to write about with regards to Robotlegs I had to break out one chunk to discuss.

Robotlegs Flow Diagram showing MVCS framework

In working with the framework, reading lots of documentation and finding it central in the diagram above, I thought it best to start with the Context class in the Robotlegs framework.

Robotlegs is an MVCS framework similar to Pure MVC that relies on metadata based dependency injection. On the surface the first cool thing is that you can use the Inject metatag to populate class fields automagically. More automagic part of the framework is that mediators automatically get created when the view they are mediating gets added to the stage. Finally it has a very elegant central event dispatcher and Command pattern model that you barely need to do anything to get working. All this is possible because of the Context.

Getting [Inject] to work

// It really is just this easy
[Inject] public var obj:MyClass;

Most of the power of Robotlegs comes from the use of the Inject metatags letting the framework. However, the framework can't inject anything until it knows what to inject. This is almost entirely done in the Context and I am going to go through the main functions here. Keep in mind that all these methods also have their inverses to undo these acts but I'll let you look those up on your own. For now I'll keep it simple and we can get to more advanced usages in other articles.

Injector methods

injector.mapValue is used when you already have a class instantiated and you want to use that object as a singleton in this application context. The basic format is: injector.mapValue(whenAskedFor:Class, useValue:Object) and might look like this:

var myObject:MyClass = new MyClass();
injector.mapValue( MyClass, myObject );

If you want to do something similar without first instantiating the object, you can use mapSingleton. The format for that is: injector.mapSingleton( whenAskedFor:Class ) and the above example would be changed to this.

injector.mapSingleton( MyClass );

injector.mapClass is used when you want the injector to create a new instance of a class every time it is asked to inject that class somewhere. The format for this function is injector.mapClass( whenAskedFor:Class, instantiateClass:Class ) and if we decided against using a singleton for MyClass instances the above examples would become:

injector.mapClass( MyClass, MyClass );

That last one may seem wierd because you type MyClass twice. However, this is because you could pass in any class that extends MyClass for the instantiateClass parameter ( or implements it if it were an interface ).

Once you've used one of these 3 commands ( or some of the others I can talk about at another time ) on all the values you want to inject in your application, anytime the framework creates or manages a class object it will have the information it needs to do just that. So how do you go about getting Robotlegs to create a class object? Automagic mediators are a perfect example.

Automagic Mediators

In Pure MVC like architectures the Mediator classes handle communication between their views and the rest of the application. Since Robotlegs is an MVCS framework based on Pure MVC this is a perfect opportunity to have the framework create the mediator for you. From the Context class you only have to write something similar to:

mediatorMap.mapView( MyView, MyViewMediator );

In this MyView is a view class and MyViewMediator is the mediator designed for it. Now the application will automagically create a MyViewMediator object when any MyView object is added to the stage and inject a reference to the MyView object into it. It will also destroy the MyViewMediator object just as magically when the MyView object gets removed from the stage. I can write much more about this in an article on the Mediator/View relationship that I plan to write in the near future.

Since Robotlegs creates the mediator it can easily inject what it needs to after it creates the class. Another class type that Robotlegs creates are Command classes.

Events, Commands and tying it all together

Robotlegs uses a centralized event dispatcher throughout to keep the model, view, controller and service sections decoupled from each other and yet tying them together at the same time. One major part of the centralized dispatcher is triggering Commands. If you've read this far, I thank you and I'm guessing you already know about the Command pattern.

To set up the command pattern in the your Robotlegs Context class just use the following format. commandMap.mapEvent( eventType:String, commandClass:Class ) which might look like this:

commandMap.mapEvent( MyCustomEvent.SOMETHING_IMPORTANT, DoSomethingImportantCommand );

Now, whenever a class in the framework dispatches the SOMETHING_IMPORTANT custom event the DoSomethingImportantCommand will be created and executed. As a bonus, the specific instance of MyCustomEvent can be injected into the command with a single line:

[Inject] public var event:MyCustomEvent;

Conclusion

So this article did not have had any sexy embedded SWF files that use Robotlegs. However, this framework's strength is not about sexy SWF files but its ease of use which should make creating that sexy file go quicker. The context file is the heart of Robotlegs and using the few methods I've written about here you can use it to make a fairly robust application linked together with dependency injection.

I've purposely left a lot out of this post. This is because I just want to wet your appetite to give it a shot as well. Also, I'd like to hear what kind of questions come up for you in the comments. Finally, I could write a lot more just about the context class and favoring configuration over convention( well sort of  ), but it would just turn into a mess of words and I'd be surprised if you read this far anyway. If you did, thank you. I'd love to hear what you think of Robotlegs if you've tried it out or even if you've decided not to.