Singletons for AS3

Posted in Programming, Tips on June 21st, 2010 by Manuel
No Gravatar

Singletons the curse and blessing of many coding projects. ;) Among other pitfalls, you’ll basically introduce a global variable in your system, making UnitTests much harder.

Why Singletons?

Despite the possible problems they can present, they are just so darn handy sometimes. If there is some part of your code that needs to be accessed from almost anywhere in the system (like the sound system, or a global error text console and such) there is hardly a better way to achieve that.

Alternatives?
A global messages system to communicate between objects can achieve the same effect. We used to make heavy use of such a system system. However, according to our experience, maintaining that system is fairly time consuming for it gets more and more complicated over time. Besides, if a messaging system allows queing, you’ll never really now where and why a message was sent because you loose the stacktrace. So, right know we are reducing the work-load done by the message system, handing it over to direct singletons access. By this, we increased debugability and clearity of data transfer. Besides, using singleton access is much faster than routing it through our messaging system.

How to Do It?
The web already offers a bunch of solutions (1). Most of them boil down to implement the singleton code over and over again in each singleton. We didn’t like that and tried to come up with a better solution. When we define a singleton it looks like that:

/**
* Accesing this class somewhere in the code looks like this:
* cSomeController.GetInstance().DoSomething();
*/

public class cSomeController extends cSingleton
{
    public static function GetInstance():cSomeController
    {
        return cSingleton.GetInstance(cSomeController);
    }

    public function DoSomething()
    {
        trace("Yes, I can.")
    }
}

That is much simpler than copying&pasting the complete singleton code over and over. The corresponsing cSingleton-class looks like that:

package rsengine.patterns
{
    import flash.utils.Dictionary;
    /**
    * Singleton base class
    */

    public class cSingleton
    {
        private static var m_instances:Dictionary = new Dictionary();
        private static var m_unlockConstructor:Boolean = false;            

        public function cSingleton()
        {
          if (m_unlockConstructor == false)

          throw Error("You cannot create an instance of a singleton."
          + "Use GetInstance instead!");
        }

    /**
    * Returns an instance of the specified class
    * @param _class class
    * @return instance of specified class
    */

    public static function GetInstance(_class:Class) : *
    {
      if (m_instances[_class] == null)
      {
        m_unlockConstructor = true;
        m_instances[_class] = new _class();
        m_unlockConstructor = false;
      }
      return m_instances[_class] ;
    }
  }
}

Our singleton implementation significantly reduced the amount of code you have to copy&paste compared to the other singleton implementations out there on the net. We do know that our implementation of GetInstance() is a little slower (because of the Dictionary look up). Since you shouldn’t have too many calls to the GetInstance method this is probably nothing to worry about too much. Nevertheless, you could cache the result of GetInstance() if you do need to access the singleton more than once (e.g. in a loop).

Have fun and happy coding
Manuel

AS3: Singletons, ActionScript 3 Singleton Redux, google

Popularity: 17% [?]

  • Share/Bookmark
Tags: , , , , , ,

Numeric Enumerations (Enums) for AS3

Posted in Methodology, Programming, Tips on April 14th, 2010 by Manuel
No Gravatar

Something I really missed in Actionscript 3 were enums. If you need ascending unique numeric ids ( e.g. for naming array indexes ), enums are your friend.

For our current project we programmed a messaging system. The system uses unique numeric ids for message types and message channels. The list of messages and channels grew over time and right now each list contains more than a hundred entries. In the beginning we did the numbering ourselves like that:


    public static const MSG_OPEN_WINDOW:int = 0;
    public static const MSG_CLOSE_WINDOW:int = 1;
    public static const MSG_REGISTER_TIMER:int = 2;
    // .. and so on

For code beauty we were always trying to group related message ids, which often meant to re-index dozens of entries if we inserted an id somewhere in between. This was a pain!

The net already has assembled quiet some wisdom about “fake enums ins as3″¹, which do fit different needs (like some have type safety) but unfortunately not ours. Most of them are String based, which is what we did not want. So after putting in some thought we came up with a solution that worked for us. Now we can define our enums like this:


    public static const MSG_OPEN_WINDOW:int = cEnum.Enum(0);
    public static const MSG_CLOSE_WINDOW:int = cEnum.inc;
    public static const MSG_REGISTER_TIMER:int = cEnum.inc;
    // .. and so on

Now, by using static methods and a static counter we can create an arbitrary amount of coherent numeric values, which comes in very handy from time to time! Re-indexing is in the past now!

We want to share our little enum class with the web, so here it comes:


public class cEnum
{
	private static var m_currentIncrement:int = 0;

	/**
	 * Adds an enum value to the collection
	 */

	public static function Enum(_v:int) : int
	{
		m_currentIncrement = _v;
		return m_currentIncrement;
	}

	/**
	 * returns the next increment
	 */

	public static function get inc():int
	{
		return ++m_currentIncrement;
	}
}

Bottom line, if you need a neat way to maintain a list of static coherent numeric entries while type safety is not a big issue … this is an fairly easy way to do it. May this help you out there as much as it helped us.

Have fun and happy coding
Manuel

¹ Further readings on AS3 enums can be found here: e.g. http://www.herrodius.com/blog/87,
http://scottbilas.com/blog/faking-enums-in-as3/
or http://blog.petermolgaard.com/2008/11/02/actionscript-3-enums/

Popularity: 29% [?]

  • Share/Bookmark
Tags: , , , , ,

Effortless Text Localization

Posted in Methodology, Programming, Server Administration, Tips on September 29th, 2009 by Thomas
No Gravatar

Automatization of repeated work is one of the keys to productive development. Another is abstraction of common problems to allow concentration on project specific work. Localization is one of the problems you have in nearly every project, especially in iPhone projects. The iPhone SDK brings interesting solutions that abstract many parts of the localization process.

The tool ibtool, for example, extracts strings from an interface automatically. The strings are placed in a .strings file, a textfile with key/value pairs. To localize an interface, you have to translate .strings and merge the strings back into the interface again. Because you have individual interfaces for every localization, it’s possible to adjust widgets individually for each one.

genstrings is another tool inside the iPhone SDK. It extracts textIDs from the source code and write them into a .strings file. You may ask how the tool knows which texts need localization and which do not. The solution is the macro NSLocalizedString, which will be replaced by a .strings file lookup method by the preprocessor, but also searched for by the genstrings tool to create the files.

Both tools help you to create a localized application without paying much attention to localization itself. But you cannot expect the localization department to search for .strings files inside your project and create localized versions of them. Of course this would be possible, but not very convenient, because you have to migrate the translated texts back into the interfaces using ibtool. Another reason for us at Rough Sea is that we use a localization interface from our publisher. This interface is well known to the localization department and the content is placed in a centralized database on a server.

So we have the great tools from Apple that help us to separate texts from the project and we have the great tool from our publisher that handles the whole translation and reviewing process. Now we need something to tie those tools together, because we do not want to insert new texts from the .strings file into the publisher’s localization tool manually or vice versa. This glue tool has to execute the Apple tools, extract the texts from the .strings files and insert them into the publisher’s loca tool. On the other hand, it has to check for new localized texts from the publisher’s loca tool, build the required .strings files from the results and merge them back into the interfaces. Sounds quite easy, but of course there are some obstacles to get there. You have to handle other things, like the deletion of a text entry or changes to an already translated interface. So you have to know what has changed since the last update and stuff like that.

It turns out that you only have to integrate this glue tool into the build process of your build server. The tool will update the localization database whenever the code or the interface changes and it will update the localized versions when the database changes. As a coder you only need to remember to use the text macro around your text id. You don’t have to add this text id in a file or anything else. As you commit your changes, the build server will do this for you. As an interface designer it’s the same: just create your interfaces in the primary language and commit it. After the localization department finishes localizing those texts, they will be inserted into the localized versions automatically. Of course you have to make adjustments to the interface if there are loca bugs like labels that are to small to hold the translated text.

As you can see those localization tools are a big black box for coders, interface designers and translators. The coders only have to write code, the interface designers design interfaces and the translators translate texts. At the end there will be a localized product.

Popularity: 66% [?]

  • Share/Bookmark
Tags: , , , , , , , ,

Asserting the Basics – Part IIb

Posted in Methodology, Programming, Tips on November 23rd, 2008 by Manuel
No Gravatar

Hello, again! We’re back with another episode of “Asserting the Basics”. Last time we talked about our assertive philosophy on error handling. Today, we go into the dirty little details: the coding of asserts.

Asserts are not something that Actionscript3 offers naturally. Consequently, I added an Assert-method to our Debug class (remember from my first post?). Its job is (of course) to check whether a Boolean expression is true, and, if not, to eventually communicate this fact. Rather than showing all failed asserts directly, our method only stores them. I want to have control over when the asserts are shown, since there are times when you actually want asserts to fail: for instance when you want to try out your error handling in Unit Tests. Thus, there is another method to take care of displaying them, which can be called at an appropriate time. So our assert framework looks like this:

private static var m_asserts:Array;
/**
 * Asserts that a condition is met
 * @param    _statement condition to check
 * @param    _msg Message to describe the assert
 * @return true if the assert failed
 */
public static function Assert(_statement:Boolean, _msg:String):Boolean
{
    if (_statement != true)
    {
        var msg:String = "****************************\n "
            + "ASSERT FAILED!!\n "+_msg+"\n"+GetStackTrace()+"\n"
            + "****************************\n ";
        // record assert
        if (m_asserts == null)
            m_asserts = new Array();
        m_asserts.push(msg);
        Debug.Out(msg);
        return true;
    }
    return false;
}
public static function ShowAsserts(_stage:Stage) : void
{
    if (m_asserts == null)
        return;
    var assertBox:TextField = new TextField();
    assertBox.autoSize = TextFieldAutoSize.LEFT;
    assertBox.width = _stage.stageWidth;
    assertBox.textColor = 0xFF0000;
    assertBox.backgroundColor = 0x000000;
    assertBox.background = true;
    assertBox.wordWrap = true;
    assertBox.text = "";
    for (var i:int = 0; i < m_asserts.length; i++) {
        var assertString:String = m_asserts[i];
        assertBox.appendText(assertString + "\n");
    }
    _stage.addChild(assertBox);
}

You may have noticed that our assert method has a Boolean return value, returning true if the assert fails. This way we can use the method to exit early from a function that would crash otherwise. Since we cannot simply take the asserts back out, we might as well use them in a bigger context.

In our code the use of these asserts look like this:

public function Load(_path:String) : void {
    if (Debug.Assert(m_fileName != null, "Filename is null!!"))
        return;
    if (Debug.Assert(m_fileName.length != 0, "Filename is empty!!"))
        return;
    // yada yada … more code
}

To give our asserts even more value, I did some research on how to get stack traces. I found out that if you throw an error and catch it in a debug player, you can retrieve a stack trace from the error object, as seen here:

/**
 * Returns the stack trace (filtered)
 * @return stack trace
 */
public static function GetStackTrace() : String {
    if (Capabilities.isDebugger == true) {
        try { throw new Error(); }
        catch (e:Error) { return FilterStackTrace(e.getStackTrace()); }
        return "";
    }
    else
        return "Stack trace not available in non-debugger version.";
}

Unfortunately, the stack trace you get this way is really extensive and hard to read. Every line in the trace contains the complete path to the corresponding file on the local machine. So, I added a filtering function to remove the unnecessary path info. This method turns e.g. this:

tests::TestDynamicTextManager.TestTextEdit()Trace:
AssertionFailedError
	at tests::TestDynamicTextManager/TestTextEdit()
	[D:\projects\programming\bgame\svn\FlashComponents
	\client\src\tests\TestDynamicTextManager.as:15]

into this:

tests::TestDynamicTextManager.TestTextEdit()Trace:
AssertionFailedError
	at tests::TestDynamicTextManager/TestTextEdit() [line:15]

Here is the filter function:

public static function FilterStackTrace(stack:String):String {
    var lines:Array = stack.split("\n");
    // remove the path
    // it's too long and we can get the info from the method trace
    var regEx:RegExp = /\w:[\\\/]([\w-]+[\\\/])*\w+.as/ig;
    var newStack:String = new String("\n");
    for (var i:int = 0; i < lines.length; i++) {
        var line:String = lines[i];
        line = line.replace(regEx, "");
        line = line.replace("[:", " [line:");
        newStack = newStack + line + "\n";
    }
    return newStack;
}

Alrighty, now you’re set to do your own asserts. Next time, I’ll talk about unit testing and Actionscript3.
So, see you in a bit for a new episode of “Asserting the Basics”.

Happy coding, Manuel

Popularity: 12% [?]

  • Share/Bookmark
Tags: , , , , , ,

Asserting the Basics – Part IIa

Posted in Methodology, Programming, Tips on November 19th, 2008 by Manuel
No Gravatar

Welcome back! Today, let’s talk about the probably most sensitive part of programming: error handling. This is a really big topic, so I made two articles out of it. This time I am going to tell you about our philosophy on that. Next time, I’ll show you how we turned our vision into reality.

Back to business: A project without proper error handling is doomed to fail after it has passed a certain level of complexity. Actionscript3 offers exceptions as a standard answer on the topic of how to deal with errors. Exceptions are for exceptional problems, but not for your little everyday error check. So, for us at Rough Sea Games exceptions are simply not enough. We like to be able to do what “The Pragmatic Programmer” [1] calls “assertive programming.” We add a lot of checks to our code to make sure we are still safe. If something goes haywire, our asserts make sure we crash early. That really helps to find the bug(ger) quickly. In addition, we like to ensure that “contracts” between methods are kept. That means, for instance, that if a method requires one of the parameters passed to it not to be null, we want to assert this to make sure it won’t happen. And if it does, we want an immediate feedback and not a some ambiguous crash further down the road.

Despite being a great help for the programmer, assertions can be a problem when it comes to performance.

Performance Issues

I did some performance tests while ago: I took out the assert method just leaving an empty stub. Oddly, this did not have a significant impact on the performance. So, the method itself is not very greedy. That’s good, but still, when I took out a couple of asserts the performance went up. How can that be? I found out that calling the method was the problem. Our assert method takes a string as one of its parameters. In some places we employed some heavy string operations to include values in that message.

When you do something like that inside an important loop you may be surprised about the great loss of performance. By refactoring some of those critical asserts, I could speed things up quite a bit without having to take the asserts out. So, if you are careful, asserts do not have to be a performance killer.

Better Production Code

Of course, taking the asserts out will produce slightly faster code, but since there is no simple way to actually take them out in a reversible manner (like using a preprocessor), we may as well leave them in for good. Some people may perceive them as a debug-only facility, but having them in production code might not be such a bad idea. We want to debug and improve our product constantly after release. A consumer that is able to tell us which assert exactly failed, helps us to find bugs a lot easier.

Well, I could go on about assertions forever … but time is scarce, so I’ll close for now. Next time, we’ll get our hands dirty and dive into our assertion code.

So, stay tuned and happy coding, Manuel

[1] The Pragmatic Programmer; Andrew Hunt, David Thomas, Addison-Wesley
ISBN 02161622X (http://www.pragmaticprogrammer.com)

Popularity: 11% [?]

  • Share/Bookmark
Tags: , , , , ,