08
Mar

AS3 is weird. True story!

Well, every experienced AS3 developer once in a while faces weird things in our beloved ActionScript 3. Sometimes it’s funny but usually it isn’t, because results in hours of wasted time. Blooddy, my Belorussian friend, compiled some of the obstacles he faced in the past into the series of short microblog posts. In this post I’ll try to translate those posts in English adding my own experience.

OK, I don’t know where to start, so the order here means nothing. Let’s start.

1. LOL! ME BROKED TEH FLASH VERIFEIRZ!!!

for ( 	var i:uint = reversed ? array.length-1 : 0;
    reversed ? i >= 0 : i < array.length;
    reversed ? i-- : i++ ) {
}

This code compiles perfectly but results in a huge bytecode dump and a weird error — VerifyError: Error #1030: Stack depth is unbalanced. 1 != 0.

Don’t ask me how I got to this code.

2. Object vs. Object

var a:Object = {};
a["a"] = 1;
a["b"] = 2;
a["c"] = 3;
for ( var v:String in a ) {
    a["a"] = 2;
    trace(v, a[v]);
}

How do you think what this code will result into? You would guess something like

a 2
b 2
c 3

But it’s actually

a 2
a 2
c 3

for me.

If you change the first line to

var a:Object = new Object();

you’ll get

b 2
a 2
c 3

Of course Adobe didn’t promise order in collections which Objects are. Also, modifying a collection while working with it looks wrong anyway. But how come new Object() and {} differ so much, as far as I remember everyone says that both these constructs create an object, the later one just can handler properties to set. Apparently it’s not right.

Actually {} results into just one opcode NewObject while new Object() results in 2 opcodes: look for class, create class (sorry, will change for actual opcode names later). Anyway, you should be aware of this fact.

3. Where did this Security Error came from?

Imagine that we have a Socket object. We want to connect to some server but it’s down. We got IO Error and want to remove all listeners from Socket events and BOOOOM! we get a Security Error because Flash couldn’t get socket policy file (undoubtedly).

Who knew that right after IO Error we’ll get a Security Error?

4. Who called this .load() ?

Imagine we have a class extending Sound.

public class S extends Sound {
  public function S() {
    super();
  }
  public override function load(stream:URLRequest, context:SoundLoaderContext=null):void {
    throw new Error( 'ZOMG PEW PEW!!!1' );
  }
}

How do you think, what will we get after executing var s:S = new S(); ?

Right, we’ll get ZOMG PEW PEW!!!1 because despite of Flash help saying “If you pass a valid URLRequest object to the Sound constructor, the constructor automatically calls the load() function for the Sound object.”, constructor actually calls .load() anyway.

5. Super()? What super()?

Continuing #4, what if we could block parent constructor of being executed… But we can’t, if you don’t specify super() call compiler will add it automatically. Well, we could add it somewhere where it won’t be executed.

if ( false ) {
  super();
}

But damn, compiler is smart. But not so smart to overcome this:

if ( !true ) {
  super();
}

Or it knows something we don’t! Apparently !true isn’t always false. But we can skip executing super constructor until Adobe fixes it.

6. GET MY CHILD BACK YOU BIATCH!!!

Imagine that we have a Container extends DisplayObjectContainer which overrides removeChild() method to throw exception so bad people couldn’t remove children from it.

Let child:DisplayObject be a child of container:Container, now look at the code

var s:Sprite = new Sprite();
s.addChild( child );
s.removeChild( child );

Apparently, it bypasses our overridden method and STEALS OUR CHILD!!!!1

7. Wait, so many loaders… I’m confused…

All the time we use loaders of different kinds: Loader, Sound, URLLoader, URLStream, FileReference. So why are they so different?

1. Loader.

  • First of all it extends DisplayObject, maybe that’s why everything loading related is in contentLoaderInfo (this is what makes me mad every time).
  • load(request:URLRequest, context:LoaderContext = null):void
  • bytesLoaded:uint (read-only)
  • bytesTotal:uint (read-only)
  • url:String (read-only)

2. Sound.

  • load(stream:URLRequest, context:SoundLoaderContext = null):void
  • bytesLoaded:uint (read-only)
  • bytesTotal:int (read-only)
  • url:String (read-only)
  • Doesn’t have httpStatus event

3. URLLoader.

  • load(request:URLRequest):void
  • bytesLoaded:uint (read-write)
  • bytesTotal:uint (read-write)
  • Also, why all URLLoader’s properties are public variables not accessors?

4. URLStream.

  • load(request:URLRequest):void
  • No bytesLoaded or bytesTotal, but at least we get a progress event

5. FileReference.

  • We get 3 methods to load data: load, download, upload
  • No bytesLoaded or bytesTotal, but at least we get a progress event

And last, ProgressEvent has properties bytesLoaded (read-write) and bytesTotal (read-write). Both of type NUMBER.

So if you want to implement your own universal loader you must know all these differences.

8. Missing TextField.

Flash says that inheritance chain for TextField is the following: TextField -> InteraftiveObject -> DisplayObject -> EventDispatcher -> Object. Apparently there’s DisplayObjectContainer missing because we can do the following:

public function test() {
  var t:TextField = new TextField();
  t.addEventListener( Event.ADDED, this.handler_addedToStage )
  t.width = 400;
  t.height = 200;
  t.htmlText = ' <img src="http://www.google.ru/logos/olympics10-hockey-hp.png" />';
  super.addChild( t );
}
private function handler_addedToStage(event:Event):void {
  if ( event.target == event.currentTarget ) return;
  trace( event.target );
}

The code results in

[object Loader]
[object Sprite]

It means that we can grab Loaders for HTML images and preload them. Also we can reparent them using the trick above (8

9. Hi, I am addedToStage! Hi, I am addedToStage!

Here’s the code:

public function test() {
  var s1:Sprite = new Sprite();
  s1.addEventListener( Event.ADDED_TO_STAGE, handler );
  super.addChild( s1 );
}

private function handler(event:Event):void {
  var s2:Sprite = new Sprite();
  s2.addEventListener( Event.ADDED_TO_STAGE, trace );
  ( event.target as Sprite ).addChild( s2 );
}

Do you expect to see only one trace? Nope, you’ll get TWO!

And here’s why. We know that addedToStage event is dispatched in the addChild() method. After executing it must tell all children that they were added to stage too. So, when we add a new object to display list in handler() it first gets its own event and after that execution flow returns back to super.addChild() where it tells all its children about them being added to stage. And there’s where the second event comes from.

Of course if we add more children objects we’ll get more misleading events.

10. __AS3__.vec

The Vector class is kind of mysterious. Flash help says that it is top level class but actually it relies in virtual package __AS3__.vec which doesn’t actually exists but is made by compiler.

Looks like a patch which is there since some early beta of Flash Player 10.

HOORAY!

That’s all for now. If you have something to add to the list feel free to mail me or leave a comment here.

Tags: , , , , , , , , , , , , , , , , , , , ,

  • http://www.jamesward.com James Ward

    These are great! I’ve been compiling a list of AS3 puzzlers. If I attribute them to you, may I use them for a possible future conference session?

    Thanks!

    -James

    • http://va.lent.in Valentin

      Sure. Would be happy for a small link to my site q:

  • http://wonderwhy-er.deviantart.com wonderwhy-er

    Good collection…
    And yeah Flash often is weird and sometimes programing for it feels like walking on thin ice… At my new job I needed to adopt to new workflow. Don’t have Flash here and work in Flex most of the time. But assets are prepared in Flash by designers… And boy this is a headache for them and me… Still adopting… May be problems are not as weird as ones you described but often they are… I think biggest problems are that loading SWF from bytearray is nonblocking and there is no way to do it a blocking operation… Would be good if both blocking and nonblocking version of this were available. Another thing is problems with how objects are initialized on timeline… Often they are not yet initialized when you get to frame, or often object it is but it’s own initial on frame script did not kick in yet and designer put something there… Thin ice it is :(

  • http://blog.iainlobb.com Iain

    Brilliant! Can we suggest our own? Try creating anonymous functions in a loop… it only ever creates one.

  • http://absulit.com Sebastian Sanabria Diaz

    For me as3 is great! but sometimes little bugs are around and is a big problem.
    I have had problems too with Vector Class, I used to use it as an Array Class, but its methods crash, so I have to use Arrays again.

    Recently I was happily using a “for each” and it never read it!, so I have to use a “for”.

    greetings! nice blog

  • http://memmie.lenglet.name Mem’s

    An other :
    —-
    var tf:TextField = new TextField();
    tf.htmlText = “du text “;
    var doc:DisplayObjectContainer = tf.getImageReference(“img1″).parent;
    trace(doc)//> [object TextField]
    trace(doc is DisplayObjectContainer)//> false
    —-

    WTF ? TextField is not a DisplayObjectContainer, but the variable “doc” can contains it?

  • http://www.victordramba.com Victor Dramba

    Cool, I could add some more..
    But it’s quite a while now since I avoid some common pitfalls in Flash because I came to know a few details about the implementation. Like for example Textfield. It is based on MovieClip inside. The AS3 wrappers are at a higher level.

  • http://robertpenner.com Robert Penner

    flash.net.URLLoader is a very small AS3 wrapper around URLStream. You can see the decompiled source here:

    http://gist.github.com/326911

    URLStream, on the other hand, is all native code. You might as well write your own wrapper around it and ignore URLLoader.

  • http://robertpenner.com Robert Penner

    #7 Loaders inconsistencies–good critique and attention to detail.

    • http://va.lent.in Valentin

      I bet this is a headache for all flash developers. Credits for details go to blooddy (http://juick.com/blooddy/563123) but he is too shy q:

  • uni

    just stumbled on your site.
    this really cracked me up

    6. GET MY CHILD BACK YOU BIATCH!!!

    :-)

  • http://www.inflatableboaters.com/ Dan

    @James: Would you mind sharing the link of the the list that you compiled?

  • http://spamurlwashere Cheska

    These are great! I’ve been compiling a list of AS3 puzzlers.For me as3 is great! but sometimes little bugs are around and is a big problem.Anyway, thanks for sharing this very useful information.

    • http://va.lent.in Valentin

      Dear bot, thank you for this great informative comment.

  • Kelly

    I’m glad that i found this post..thanks for the warning..now i have an idea so i’ll keep this in my mind..Thanks again for such a very informative post..Great content!!

  • http://www.**.com/ Robert Sharp

    I like AS3, i did get a big headache trying to figure these outs. Thank for the information it helped me out a lot.