Moving to Flash, Part 2: Important Differences Between Java and ActionScript 3
In my last post I mentioned that we are moving to Flash. The response has been crazy, just check out the comments there. In the next few posts I will highlight some of our experiences in doing the port. It’s been an interesting ride… stay tuned for more.
![]() |
There are a couple of places you can go to see what the main differences are between ActionScript and Java. Most of those posts address syntactical differences in the languages. In this post I’ll highlight the things that were either really important or a big problem for us and what you might want to address before undertaking a port to Flash.
Data Structures
I’m putting this item at the top because I cannot stress how important it was that we used our own interfaces to data structures for arrays, stacks, maps, etc. rather than relying on Java’s implementations directly. ActionScript only supports Array and Dictionary; no stack, no linked list, no queue. If you performed a port to ActionScript and were relying on these Java classes, you would be in trouble. If, however, you used your own interfaces for all of the data structures, you will only need to re-implement the data structures that you are wrapping, saving you a ton of time.
Interfaces
I dislike ActionScript Interfaces for one reason: no data members. What does this mean? For every high level type of object that you have, you are probably going to need another class for the constants associated with that class. It isn’t a huge deal but it contributes to code bloat and is a pain in the butt when you’re porting all the references to data members in the interface. Other than that, they’re identical to Java.
Abstract Classes
The lack of true abstract classes in ActionScript means that you must implement every method in an interface in a class that provides limited functionality from that interface. This can be done via the “virtual” keyword, but as with the interface issue, it also adds to code clutter and doesn’t seem truly necessary. If you have a lot of abstract classes in the chain from an interface to the concrete class, this gets annoying and messy.
EDIT: It seems that functions are declared virtual by default, so using this keyword does not provide any shortcuts, and you still need to declare the function bodies. It is unclear what exactly the virtual keyword does.
Anonymous Inner Classes
I’ll be addressing this one in a later post as well because it can lead to a lot of problems depending on your architecture. Suffice it to say that ActionScript lacks anonymous inner classes. If you use the Decorator or Adapter patterns the actual implementation can be a burden. As you’ll see, it pushes errors from compile time to runtime which can make development much more difficult.
Anonymous Functions
Java doesn’t have anonymous functions. Anonymous functions are actually really cool, except for one problem: what appears to be the lack of a local activation stack. Take this ActionScript code:
var i:int = 1;
|
You get a print out of “2.” This can be incredibly confusing if you’re debugging complex code. In Java, you would have had to declare your variable as final and you could use it to your hearts content inside a method, such as a Runnable. In Flash, you need to create an additional local copy of the variable that is only used inside the function and initialize it to the desired value.
Another important point: anonymous functions are not compile-time checked for the number and types of parameters that are passed in, pushing more debugging off to runtime.
Exception Handling
Exception handling is pretty similar in ActionScript and Java, except for one big thing: There is no “throws” declaration in ActionScript. These types of problems are along the same lines as my biggest complaints with ActionScript: it makes debugging the application so much harder.
The availability of a “throws” declaration requires the programmer to handle the exception or pass it up to the caller. In either case, the programmer is acutely aware that there is an exception that might get generated as the result of calling a method. Without this, exception handing can propagate up the call stack until it is finally handled, causing unexpected runtime issues.
Function Overloading and Default Parameters
ActionScript does not allow the programmer to overload functions. This isn’t a huge problem, as they do allow for default parameters. In java, I might write:
public void defaultSetter(int iValue) {
|
In ActionScript, I write
public function setter(iValue:int, bForce:Boolean = false):void { |
I like it. What I don’t like: what if you have multiple setter methods that take different types? Well you end up with a lot of functions like setFromString() and setFromInt(), etc. Fine. But, what if your constructor is the one being overloaded with different parameter types? Now you need a factory for your objects (which maybe you should have anyway…), which means more code bloat. There may be other ways to get around this via setters but refactoring that functionality can be a pain.
Nested Classes
ActionScript also lacks nested classes. Again, for Decorator or Adapter patterns this can be troublesome. It means that you need package-private access to functions or data members, slightly breaking some of the object oriented rules.
Recommendations
If you know about these problems then you can act before hand. If you have a project you want to port to Flash, use your IDE to do address these some of these issues before you perform the actual port. Learn to use the refactoring tools. It will make your life so much easier. Here are some tips:
- Wrap references to language-specific data structures in your own interfaces, even if they’re just pass-through.
- Pull data members out of interfaces into their own constant classes.
- If possible, name your anonymous inner classes and put them in their own file. A later post will address often-used anonymous inner classes such as Adapters.
- Pull out nested classes into their own files.
- Create Factories for classes that have lots of different types of constructors.
- Refactor setters that take different types of parameters. You can address default parameters after the port.
I’ll be following up this post with some thoughts about beginning the actual port to ActionScript. Check back soon!
Tags:ActionScript, Flash, Java, porting
6. November 2008 at 2:09 pm :
You might find it interesting to have a look at the haxe language at http://www.haxe.org. It’s syntactically similar to javascript, and has a pretty steady parser generator that, right now, compiles to as (6-10),js,php and a vm called neko (running cross platform), with a c++ generator in the works.
It solves the following problems from your list in the following way:
1) DataTypes: List, Hash and Array, with an Iterable type to support built in iteration[ for (value in array){} ]. Also, these datastructures, are typed:[ new Array()].
2) Interfaces can declare private and public functions and values
3) Haxe supports typedefs and enums, for what it’s worth.
Obviously, it’s not a complete solution, but there’s some interesting stuff going on, and for the more technical side, you might want to talk to the coder, for example, would it be possible/ does it already generate a local activation stack from the ast? I don’t know. I’m sure he’d be willing to listen to any changes that don’t go directly against design decisions.
Oh, and there’s a project in the works(alpha) to automatically port as3 code to haxe, so you might want to go check it out. I’m interested to see what design choices you make going from a multithreaded environment to a single threaded one, if you get into that here,
6. November 2008 at 2:58 pm :
I’ll have to check haxe out. As you mentioned, it wouldn’t be a complete solution but it could potentially offer our decent port of some of our core functionality. I’d be a little worried about language-specific performance issues but it would be nice to avoid some of the intricacies of AS.
I will in fact address some of the issues of moving from Java’s multi-threaded environment to Flash’s single-threaded one. Check back soon, I’d be interested to hear what your thoughts are.
6. November 2008 at 4:09 pm :
Michael Baczynski’s “AS3 Data Structures For Game Developers” contains excellent implementations of Stack, Linked List, and Queue.
http://lab.polygonal.de/ds/
http://code.google.com/p/as3ds/
6. November 2008 at 4:54 pm :
@Eric thanks for posting those links. I’ve seen these although we aren’t currently using them. The important point is that you have your uses of a language’s data structures are wrapped, it should be easy to use implementations such as the ones you’ve provided under your own interfaces. You shouldn’t have to write your own (nor did we).
6. November 2008 at 5:18 pm :
Someone at one of the conferences had Quake running in AS3 using, I believe, a byte code generator, and green thread implementation. The closest thing I’ve seen in the public domain is lowra: http://osflash.org/projects/lowra, which has an inner loop that you can message with iteration commands to be run asynchronously so as not to cripple the ui under heavy loads.
As for performance, there are some tests at http://gamehaxe.com/category/result/ (bearing in mind some are over a year old) , which goes into things quite thoroughly. There is, if the adobe compiler is faster for a given thing, the ability to save the intermediate as3 generated by the haxe compiler, and run that through mxmlc. Additionally, there is a library (hxasm) that allows you to write swf assembly code directly, the ability to mark functions as inline, and some optimisations built into the code generation.
As for avoiding the intricacies of AS, I’m not completely sure what you are referring to. The display object hierarchy and drawing api are almost unchanged from AS3, given that it’s a platform specific portion, but the Reflection API is much more solid than the XML based one shipped in vanilla AS3, the type inferencing is mostly excellent, and lambda parameter and return types can be set[ Dynamic->Void (takes dynamic, no return) ].
I’m not sure if there is a unifying abstraction for event-driven/multithreaded programs. The actor model might provide the answer i’m looking, but I’ve yet to explore it. That said, I’ll be happy to contribute what I can.
6. November 2008 at 5:30 pm :
@Ob1Kn00b The next two posts will talk about some of those intricacies. It’s mainly when you get into dynamic classes and anonymous functions. I’m constantly annoyed that so many problems don’t show up until compile time. It’d be nice if haxe took care of those issues. Thanks again for the info, I’ll look into the links you posted.
6. November 2008 at 8:24 pm :
AS3’s implementation of a Dictionary leaves so much to be desired that I would go so far as to suggest not using it in any way. It functions similar to its array in that it returns a key to an index, and has only unique keys. Beyond that though there isn’t any functionality. You can’t get a list of keys, or values. When I say it in the documentation, I felt lulled into thinking it had all of the Java functionality (or python for that matter), and was surprised badly when I found out.
I also had problems with the implementation of ‘in’, and how it had at least three different behaviors. I wish AS3 would emulate python for this.
One last problem I had was in using AS3, I used it w/o any of the build tools, except for mxmlc, and mmc. You hit this point in your last post about the compiler leaving a lot to be desired, but it really does need some help. Mmc was the only way to quickly rebuild projects, but I find it strange that the up key to repeat a command only being functional in the windows command line strange.
I do like AS3, and whenever I look back at AS2, I am glad I never learned it first. I really think it is becoming a language that in a few more stages will support both developer and artist nicely. I just feel that there are good amount of little gotchas when coming in from the Java world. This is also a big reason why I like this set of articles you are writing.
(also I really like the var:type declarations, they bring back fond memories of pascal)
6. November 2008 at 11:26 pm :
@morgan I’ve been pained by the Dictionary as well. There are a lot of cases where we need to loop over objects in a hash map. If you do this naively, that means that the underlying data structure needs to create a copy of all of the keys and return them. This is time consuming and requires the creation of more objects, resulting in other issues such as more garbage collection.
However, if you have in fact wrapped your data structures you can add (or might already have) functionality for returning an iterator interface to the data structure. Under the hood, this can take care of some of the efficiency issues while maintaining your abstraction.
You’re right though, there are enough little gotchas that things like this are really important to point out. I hope that the following posts will help with some of them.
7. November 2008 at 10:55 am :
Speaking of exception handling:
There is also no way to do a top-level exception handler (that handles all uncaught exceptions), and this is especially problematic on the non-debug version of the player, where when there is an uncaught exception there is no indication that an error has occurred. Vote on this issue if you care about it: https://bugs.adobe.com/jira/browse/ASC-3139
7. November 2008 at 3:02 pm :
Anonymous Functions: No local activation stack
| var i:int = 1;
| var tFunction:Function = function() {
| trace(i);
| }
| i += 1;
| tFunction();
ECMA Script has full closures, so they capture the lexical scope that they were defined in.
Redefining your example:
function getFoo(x:int) {
var i:int = 1;
return function() {
trace(x);
trace(i);
}
}
getFoo(2)(); // 2, 1
getInc(3)(); // 3, 1
The behavior complaining about isn’t a problem it’s a feature. If you wanted it to have a different i, make a new i in the local scope and use that one.
Here’s a somewhat contrived example using this behavior.
function getCounter(start:int):Object {
return {
inc: function() {
start += 1;
return start;
},
dec: function() {
start -= 1;
return start;
}
}
}
var x:Object = getCounter(2);
x.inc(); // 3
x.dec(); // 2
var y:Object = getCounter(11);
y.inc(); // 12
x.inc(); // 3
7. November 2008 at 3:12 pm :
In regard to the multiple setters, could you not use:
public function set foo(bar:*):void {
_foo = bar as FooType; // could also be int, Number, String, whatever.
}
You could check to make sure it’s of a certain type prior to trying to assign it to _foo, to make sure that the type can be converted to a FooType. If it doesn’t match, just throw an error.
And maybe I didn’t understand the “lack of a throws” comment you made, but you can just do:
throw new Error(”Description of the error”);
You can extend the Error class as well.
7. November 2008 at 3:26 pm :
So, there’s an obvious cultural shift between these two languages that reminds me of an experience I’ve had over the last year or so.
I’ve been playing around with Python for the last few months, and one of the really jarring things about Python development for me (coming from a C/C++/Java background) is that most problems are runtime problems. There’s no compile-time type system, functions and classes are created at run-time, so calling a method that doesn’t exist can’t be caught immediately (since by the time we make the call, someone might’ve added that method), etc.
So, how do you avoid getting surprised when the software’s in the customer’s hands? The Python community uses unit testing pretty extensively. Unit tests are, in a sense, a way to test your run-time assumptions at “compile” time, or at least all at one time, easily and quickly. The up side of them is that you get to include whatever run-time assumptions you want. The down side is that they’re a bit more work, obviously.
I’ve yet to personally do TDD on a large scale (or use Python on a large scale), but it seems to work reasonably well for a lot of projects. And even if you’re not doing TDD, you can still use unit tests as a debugging tool, which may or may not be of some help.
I don’t know, maybe you’ve already got unit tests in place, but if not, I’d suggest considering them, even if you eventually decide not to make them a part of your development process.
Finally, regarding checked exceptions, I’m rather amazed that when moving to a language without them, your reaction isn’t “good riddance!” In “Thinking in Java, 3rd Edition” I believe Bruce Eckel advocates wrapping all checked exceptions in RuntimeExceptions to be rid of that mechanism. If you’re interested in hearing why, he’s written about it a bit on his website: http://www.mindview.net/Etc/Discussions/CheckedExceptions . I’m certainly not belittling you for liking checked exceptions, and they kind of help move problems from run-time to compile-time, but again, with proper documentation (perhaps backed up by testing, preferably automated), I don’t think unchecked exceptions need to be a problem.
7. November 2008 at 3:27 pm :
@John I shouldn’t have said that it is a problem but rather that this is something to look out for. Your examples do a good job of highlighting how this feature can be useful. The place where I found the functionality to be confusing is when you were looping over an array and using a value inside the function. I probably should have added this to the post, but here’s an example:
| var iSize = tArray.length;
| tObject = tArray[i];
| var tObject:Object;
| for (var i:int = 0; i
|
| var tNewFactory:MyFactory = new MyFactory();
| tNewFactory.addImplementation(function():Object {
| return tObject;
| });
|}
The value of tObject will always be the value of the last object in the array. As I mentioned in the post, you would have to declare a copy of your variable to final to use it in this way. I didn’t do this initially and it was a tough problem to figure out.
The example above is a bit contrived so my solution won’t make sense in that context. In the end, I fixed it by passing in the required data to the function.
7. November 2008 at 4:12 pm :
@Alex yes, you could use setters that way. My personal preference is to require type checking so that an invalid object can’t be passed in. This gets to your next question, and the crux of the next comment, Ben’s, which largely has to do with checked exceptions. The article he posted is great, so check it out for a better description.
@Ben I do think that we’re going to have to get better about writing unit tests. We did quite a few of them in the beginning but have lost the habit a bit.
I’m fascinated by the article. I don’t necessarily agree with it all, but you’ve began tipping me in that direction. I’m thinking about an example of initializing our applications with persisted data. Our assets are inherently hierarchical, and fairly deep. Each object in the hierarchy has its own initializer and any number of problems can happen during that initialization. Our initialization exceptions can be handled at each level, and generally are, in order to ensure that the majority of a particular object can be initialized even where there are problems and relevant problems can be fixed.
That all being said, I respect the use of the exception adapters as pointed out in the article. I’m starting to think that a mix of the two solutions might be a good one. I still think that there is a problem with an un-handled runtime exception propagating too far up the execution stack. Once runtime exceptions are being thrown, the programmer isn’t necessarily aware of the types of exceptions that could or should be handled either. I don’t think either option is ideal, and I admit that I could have missed something in the article as I skimmed through it quickly. But, I could see a case where some simple exceptions are wrapped and thrown while others must be checked.
9. November 2008 at 4:06 am :
Just wanted to say thanks for posting all this stuff. I’m in the process of porting some of my stuff and you’re providing me a really good shortcut to finding the issues and problems without using trial and error.
Thanks again!
Kev
11. November 2008 at 7:19 am :
Nice article and a couple of good points!
However there a two very important (in my humble opinion) things missing in your list which may very well break your neck at a later time during the port:
Flex does not have Object.hashCode() so say bye bye to implementing your own HashMap that works well with any kind of Flex object. Using Dictionary or object is not an option for various reasons.
Secondly (and that may be more crucial) Flex does not have Object.clone() and there is absolutely no way you can workaround this if this is not supported by the runtime. The single most important thing missing here is that Java’s Object.clone() or C# object.MemberwiseClone(); creates a new instance without calling the constructor and that is impossible using pure AS3. It is extremely ugly and sometimes impossible having to implement the constructors so that they *all* take a flag that tells the constructor not perform the initialization (which might be enough for a crude clone implementation but most of the time is not.
11. November 2008 at 10:14 am :
@Sebastian Thanks for the comment. I’m guessing you haven’t seen the next article in the series though (http://blog.sharendipity.com/moving-to-flash-part-3-beginning-the-actual-port). This addresses a solution to the hashCode() problem you mentioned, although I do not address the Object.clone() problem.
We don’t actually use Object.clone() at all. In the past we have used copy constructors that do the cloning themselves. With the move to ActionScript, these constructors have been moved into factories to address the lack of duplicate function definitions. This is touched on above in the section labeled “Function Overloading and Default Parameters.”
12. November 2008 at 5:17 am :
A very nice in-depth article.
I didn’t know there is the “virtual” keyword in AS3. It is not documented in http://livedocs.adobe.com/flex/3/langref/statements.html. Wonder how come so many features of AS3 are hidden.
12. November 2008 at 8:48 am :
@yuku I actually wasn’t aware of it until well into our port either. Even looking now, it’s hard to find information about how “virtual” is meant to be used. I found it because Box2D, the physics engine we use, has several declarations that use it. However, it appears from a few forum posts that I’ve found that it’s just ignored. Indeed, defining a function as “virtual” does not cause compiler errors is the derived classes do not override it. Forum post here: https://defiantmouse.com/yetanotherforum.net/default.aspx?g=posts&t=82. I’ll update the post.