The Sharendipity Blog » Post 'Moving to Flash, Part 3: Beginning the Actual Port'

Moving to Flash, Part 3: Beginning the Actual Port

In the past few posts, I’ve mentioned why we’re moving to Flash and some of the things you should know before you try to do so yourself. I recommend reading up on it:

Part 1: We’re Moving to Flash. Here’s Why

Part 2: Important Differences Between Java and ActionScript 3

In this post I’ll talk about starting the actual port and addressing some of the things that are much harder to do beforehand because they would cause compile time errors. Many of these are syntactic changes but there are some other important points about data structure usage. The following posts will address some more advanced topics.

J2AS3

This little project helped us out immensely. It allows you to translate Java code to ActionScript 3. I modified the project slightly to take a directory and recurse through it to write out every Java file but other than that we pretty much used it as-is.

J2AS3 will get you most of the way there although there is still a lot of work to do.  There are a few bugs in the project but nothing you can’t get through.  The simpler issues that you will still have to fix will be highlighted in the post. The following post will describe some of the core logic changes that you’ll have to perform.

Getting Started with ActionScript

Now that you have a bunch of ActionScript files to work with, you need something to edit them.  The Flex Builder IDE is decent for working with ActionScript files, but not great.  There is also a 60 day trial so you can at least try it out.  One suggestion: if you’re doing a lot of syntax changes then you probably want to turn off Build Automatically. The compiler is pretty slow and will try to recompile an entire project every time you make a change.  Is is also missing a few other features such as simple code formatting.  For syntax changes, you might want to find another editor.

String Equality

We work a lot with XML so we do a lot of string comparisons to determine what particular node you are dealing with.  Java’s string equality uses the equals() method. ActionScript uses the == operator. So a simple line such as:

sString1.equals(sString2)

becomes

sString1 == sString2

This is significant only because it takes time to do the manual translation. I used the Find/Replace functionality to go through files one by one to ensure that we are only replacing string comparisons with this method and not other object comparison.

Exceptions

ActionScript does not have an Exception class, everything is derived from Error. It’s easy enough to change your custom exceptions to extend Error, but what about the stock Java exceptions, such as NumberFormatException, RuntimeException, etc.

In a lot of cases, I created our own exceptions that mirrored those of Java. This is easy as well, but the actual logic can be difficult to handle. Take NumberFormatException, for example. Java’s Integer.parseInt(java.lang.String) will throw a NumberFormatExcpetion if it can’t parse the string. If you’re using that code and relying on the exception, then you probably have statements like this:

int iValue = -1;
try {
    iValue = Integer.parseInt(sValue);
}
catch (NumberFormatException tEx) {
    // handle exception
}

In ActionScript, a port of your code would change to:

var iValue:int = -1;
try {
    iValue = parseInt(sValue);
}
catch (tEx:NumberFormatException) {
    // handle exception
}

Obviously, ActionScript won’t throw the NumberFormatException because you just created that class, so what should you do? My suggestion is to use utility classes. Lets say you have a StringUtils class, then you could define the following function:

public static function getInt(sValue:String):int {
    var tTest:* = sValue;
    if (sValue == null || sValue.length == 0 || sValue.indexOf(".") >= 0 || isNaN(tTest))
        throw new NumberFormatException("Value was not an integer: " + sValue);

    return parseInt(sValue);
}

This will allow you to leave your exception handling intact while porting only the integer parsing, which you’ll have to do anyway. It’s kind of a pain but if you’re porting from Java you probably need to be able to replicate the same functionality that Integer.parseInt() has. Other exceptions such as IOException can be a little more straightforward because you might just need to catch something else (if ActionScript throws it).

Runnables

The fact that ActionScript is inherently single-threaded doesn’t mean that you can’t use runnables. In fact, in a later post, we’ll see that in addition to a task manager this might make porting some of your code easier.

The Runnable() class in Java provides a single method: run(). In ActionScript you can create your own Runnable class that has its own run function. One way to use your own runnables is to create new classes that extend your new Runnable class and override the run() function. There’s another way to do it without creating an additional class. That’s what we’ll take a look at next time.

Synchronization

You don’t need it. If you only synchronize methods, you should be able to do a global search and replace on the synchronized keyword. If, however, you use double-checked locking or synchronize on mutex objects you might just need to do it a little more manually. Eclipse’s Find/Replace functionality works well here.

Using instanceof

I’ll avoid my rant about using instanceof at all. Sometimes it’s necessary. However, ActionScript’s notion of instanceof is a little different than Java’s. It has the same functionality as the Object class’ isPrototypeOf() function. This does not return true if you are testing whether or not the object implements an interface. For this, you want to use the “is” operator. It should be alright to just do a global search and replace for this, but I always like to be safe and go through the changes one by one.

Similarly, casting will use the “as” operator. In some cases, the translation with J2AS3 will work fine, but not always. You’ll get a compile error and you’ll just have to go fix them.

Function overriding

If you’ve read my last post, you probably know that a lot of my complaints about ActionScript have to do with the class architecture. Function overriding is another case of that. Functions must use the override keyword to say that they override another function. No big deal, but the translation here is pretty manual.

Breaking out of finally statements

There is a nasty bug that has to do with having multiple exit points in a finally clause. The only reason I mention it here is because it came up more than once in our code. Something of the form:


for (var j:int = 0; j<10; ++j) {
    try {
        trace("j: " + j);
    }
    catch (tEx:Error) {
        // handle error.
    }
    finally {
        trace("finished.");
        break;
    }
}

will throw this error:

VerifyError: Error #1030: Stack depth is unbalanced. 0 != 1.

If you run across this, just keep a boolean outside your loop for whether or not you want to break and check that in your for-loop.

Array Creation

J2AS3 doesn’t quite get declarations for array creation correct, but it comes close. The problem is that you won’t get a compile error from the statement:

var tObject:Array = new Object[10];

Instead, you get this error during runtime:

TypeError: Error #1007: Instantiation attempted on a non-constructor.

I went through our code base searching for the expression “new*[*]” with Flex Builder and was able to find the places where this was an issue. I still find myself typing that in by habit as well.

hashCode()

Objects in ActionScript do not, by default, have a hashCode() function. Java does. In Java, you can override the hashCode() method so that two different objects can map to the same location in a Java HashMap. This is really handy, so how do you provide this functionality in ActionScript?

ActionScript has a Dictionary class which can be useful (and as a commenter named morgan pointed out in the last post, it also has some issues).  In ActionScript, the object’s ID is used as the key for the Dictionary. If two objects have similar internal IDs, you need a way to map those objects to the same location in a HashMap.

I found a HashMap implementation here that was very useful as a starting point. It does not, however, allow for mapping of objects based on a hash code. In order to do that, I needed to make my own HashCodeHashMap.

What was really nice was ActionScript’s handling of functions. There is also a HashMapEntry class that came with the code that I used that made this easy. I created a new version of the HashMap that could be used for objects that defined a hashCode() function. Here’s my new put() function for the class to give you an example:

public function put(key:*, value:*) : void

    if (key != null) {
        var tHashMapEntry:HashMapEntry = new HashMapEntry(key, value);

        var tNewKey:*;
        if (key.hasOwnProperty("hashCode"))
            tNewKey = key.hashCode();
        else
            tNewKey = key;

        map[tNewKey] = tHashMapEntry;
    }
}

This code assumes that the hashCode() function will return an integer, which is a pretty safe bet if you’re porting from Java to ActionScript. It should in fact work regardless of what hashCode returns however, because the Dictionary will use the object ID for mapping. This code will also work with objects that don’t implement hashCode() but I use the original HashMap for those for performance. However, I haven’t profiled the new class yet and I’m guessing that this is a bit slower than the original code.

Iterating over HashMap Entries

In the last post I talked about wrapping data structure usage with your own interfaces. The previously mentioned commenter talks about the lack of functionality in the Dictionary class.  Using your own implementations allows you to address some of these problems. The commenter also points out the ActionScript 3 Data Structures (AS3DS) project, hosted on Google Code. The HashMap class is a good implementation to use for iteration, allowing you to loop over the keys or values without having to create an Array and copy all of the objects into it.

Conclusion

If you’re actually doing a port, you’re well on your way to having a functioning prototype at this point. There are a couple of other problems that you’re going to come across. I have at least two more posts planned for the series so check back, or better yet, go grab the RSS feed. We’ll certainly let everyone know when our prototype goes live.

Bookmark and Share
Tags:, , ,

12 Responses to “Moving to Flash, Part 3: Beginning the Actual Port”

  1. Hi Dale,

    How can we use the contains () method of ArrayCollection in actionscript similar to the contains() in java collection

  2. Interesting set of articles. I am not sure if you are aware of the things I am about to write here, if you are not, this might save you some headaches.

    ‘Similarly, casting will use the “as” operator.’

    In Actionscript there are two types of casting:

    1. var obj:Type = otherObject as Type;
    2. var obj:Type = Type(otherObject);

    The difference between the two is that 1 will result in a null value of otherObject is not an instance of Type. 2 will throw an error if otherObject is not an instance of Type.

    In most cases option 2 is preferred, there are however cases where this can cause strange results. Actionscript has for build in classes global functions which act as constructors. The most common one that will give strange results is array. If you want to cast an object to an Array with option 1, it will result in an array containing otherObject at index 0.

    ‘key.hasOwnProperty(”hashCode”)’

    This will only work for properties or methods that have been dynamically added. If properties or methods are class members, the above method will return false. There are two ways to check if an object has implemented a certain method:

    1. Call the method and catch the error
    2. Use the describeType method to find out if the object implements the method.

    It would be better in my opinion however to create an interface that defines the hashCode method and then use the ‘is’ operator to check if the interface was implemented.

    Greetz Erik

  3. @Pavan Kumar as I mentioned in the previous post, if you’re wrapping your data structures with your own implementations, it’s easy to add this type of functionality. In your case, it seems that the problem is that you don’t want to use strict equality (this is the same issue as with the Hashmap above). You could accomplish this by having your objects implement an IComparable interface which is used in your own array implementation’s contains function.

    @Erik I was aware of the casting behavior you mentioned. When porting with J2AS3 you will get the second type of cast. I haven’t seen the behavior that you mentioned with the array yet so I’ll have to watch out for that. As for the hasOwnProperty() functionality, it doesn’t seem that what you’re saying is quite right. I wrote up two quick test cases:

    |public class Test1 {
    | public function Test1() { }
    |
    | public function hashCode():Number {
    | return Math.random();
    | }
    |}

    and

    |public dynamic class Test2 {
    |
    | public function Test2() {
    | this.hashCode = function():Number {
    | return Math.random();
    | }
    | }
    |}

    My test code then, looks like this:

    |var tTest1:Test1 = new Test1();
    |if (tTest1.hasOwnProperty(”hashCode”)) {
    | trace(”hashCode for test1 exists: ” + tTest1.hashCode());
    |}
    |
    |var tTest2:Test2 = new Test2();
    |if (tTest2.hasOwnProperty(”hashCode”)) {
    | trace(”hashCode for test2 exists: ” + tTest2.hashCode());
    |}

    which results in:

    hashCode for test1 exists: 0.71109629701823
    hashCode for test2 exists: 0.25985044334083796

    This also seems to work fine for inherited classes. From what I can tell, this is the expected behavior and is described this way in the documentation: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/Object.html#hasOwnProperty(). If I’ve missed though something please let me know.

    In any case, I do agree that it would be better to implement an interface for this.

  4. “it doesn’t seem that what you’re saying is quite right”
    .
    Indeed, they must have fixed it in one of their releases. When Actionscript 3 just came out it did not work. I totally assumed that the method was meant for dynamic classes and never tried again.
    .
    Thanks for trying and letting me know :)
    .
    .
    Greetz Erik

  5. Is it still possible to get the J2AS3 source code? The .zip file pointed to on the project’s page seems to no longer exist.

  6. Ok, I found it at http://thunderhead.esri.com/readonlyurl/J2AS3.zip. Hopefully that is the most recent build.

  7. Apologies for posting in response to myself so much, but apparently the one on thunderhead is out of date. It crashes quite easily on a lot of my code.

    I wonder if the most recent version is available anywhere?

  8. I accidentally stumbled upon another operator that does the same as hasOwnProperty: in.
    .
    if (someProperty in object)
    .
    .
    Greetz Erik

  9. @Erik Are you sure? I can’t reproduce this, and it sounds real handy. It’s also not documented in the AS3 Language Reference.

    If you’ve got some sample code, by all means!

  10. It indeed is not in the documentation, but used quite often in the Flex library apparently.
    .
    var o:TestClass = new TestClass();
    o.prop1 = “soup”;
    o.prop2 = 2;
    .
    if (”prop1″ in o)
    {
    trace(o["prop1"]);
    }
    .
    if (”prop2″ in o)
    {
    trace(o["prop2"]);
    }
    .
    .
    Greetz Erik

  11. Hi, I can’t understand how to add your site in my rss reader. Can you Help me, please :)

  12. You can subscribe using the following link… http://feeds.feedburner.com/SharendipitousMoments

Leave a comment

© 2009 The Sharendipity Blog is powered by WordPress