Clash of the Instance Names

“What do you mean it’s weird to give the same instance name to different library symbols, on different frames of the same timeline?”

As you probably know, the world of Flash Development is populated largely by people who aren’t from a traditional programming background. The early iterations of ActionScript were incredibly lenient and forgiving in terms of the sort of… odd… things it would allow a developer to get away with. If ActionScript were one of your first languages, you might not even think of such a thing as odd! Things such as this…

A clash of instance names in the Flash IDE
Illustrating the root of the conflict.

The really big mistake here is that all of these library items inherit from the same user-defined Base Class, com.scriptocalypse.NewMovieClip.

package com.scriptocalypse {
	import flash.display.MovieClip;
	import flash.text.TextField;
 
	/**
	 * ...
	 * @author The Horseman @ Scriptocalypse.com
	 */
	public class NewMovieClip extends MovieClip{
 
		public function NewMovieClip() {
			trace(this + " instantiated.");			
			this.stop();
			this.mouseChildren = false;
			this.text_txt.text = this.toString();
		}
 
	}
 
}

Those of you still fresh out of AS2 might be scratching your heads over why this is suddenly an error of grave consequence. “I’ve been doing that for years, and nothing bad has ever happened!” Those of you from more traditional programming backgrounds might be scratching your heads over the entire thing and wondering “Why in the world would you want two instances of two different Classes to have the same instance name on the timeline? Foo is Foo, and Bar is Bar.”

I’ll address the latter first: Early versions of ActionScript were perfectly capable of accommodating this, and in fact this made it incredibly quick and simple to use a frame-based state transition scheme. If you wanted a different visual state to have a different style button, and you also wanted to take advantage of the timeline for using visual transitions without having to write new code for every state view, you could do that very quickly and easily. You could have Foo000 be your “back_btn” on frame 1, Bar000 be your “back_btn” on frame 2, and AwsmeBtn be your “back_btn” on frame 3. The AVM1 simply did not care. As long as something had the instance name in question, it would use that and not care one bit about type-safety at runtime.

For the AS2 migrants, that bit about runtime type-safety is the reason you can’t get away with this anymore. See, what Flash does when you publish your swf is create a lot of code for you that you probably weren’t aware of. Let’s say your document class looks like this:

package com.scriptocalypse {
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
 
	/**
	 * ...
	 * @author The Horseman @ Scriptocalypse.com
	 */
	public class DocumentClass extends MovieClip{
 
		public function DocumentClass() {
			this.stop();
			this.foo_mc.addEventListener(MouseEvent.CLICK, onClickFoo);
		}
 
		private function onClickFoo(e:MouseEvent):void {
			this.gotoAndStop(this.totalFrames);
		}
 
	}
 
}

That foo_mc you put on the timeline… how does Flash know to reference it, or even what it is? There’s a checkbox that is selected by default in the Flash IDE.

Click File -> Publish Settings -> Flash -> Click the “Settings…” button next to the ActionScript 3 dropdown.

Do you see a checkbox marked “Automatically declare stage instances”? When you have that box selected, your code above is modified by the compiler when you publish the swf. It ends up looking more like this:

package com.scriptocalypse {
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
 
	/**
	 * ...
	 * @author The Horseman @ Scriptocalypse.com
	 */
	public class DocumentClass extends MovieClip{
 
		public var foo_mc:NewMovieClip0; // Where did this come from?????
 
		public function DocumentClass() {
			this.stop();
			this.foo_mc.addEventListener(MouseEvent.CLICK, onClickFoo);
		}
 
		private function onClickFoo(e:MouseEvent):void {
			this.gotoAndStop(this.totalFrames);
		}
 
	}
 
}

Notice that Flash helpfully wrote this for you. Notice also that the datatype is the “Class” field in the library. Now, you’ve got about 5 frames worth of these foo_mc instances on your stage. This is kind of a problem! Flash wrote that instance in your class and gave it the same variable name as your NewMovieClip0′s instance name. What is Flash supposed to do with the other 4 instances? It can’t rename them for you, and it can’t create new and oddly named variables for them… you wanted a variable on your DocumentClass called foo_mc and you’re going to get it!

So you compile. You may or may not get a compiler warning, but it succeeds regardless! The swf can play. So, you’re sitting on Frame 1 as happy as you can be. You then click a button to attempt to go to the last frame, but then find that bedlam has broken loose. Here’s your output window:

[object NewMovieClip0] instantiated.
[object NewMovieClip4] instantiated.
TypeError: Error #1034: Type Coercion failed: cannot convert NewMovieClip4@4e3f421 to NewMovieClip0.

This happens any time you try to coerce a class into “being” something that it isn’t. While it is true that both NewMovieClip0 and NewMovieClip4 are “NewMovieClip” subclasses, and if foo_mc had been declared as a “NewMovieClip” instance by Flash they could be coerced freely… but they are not declared as the more general “NewMovieClip” and so cannot take advantage of polymorphism and fit inside this NewMovieClip0-shaped “container.”.

This behavior can, depending on your Flash Player version, lead to all manner of incredibly bizarre and hard-to-diagnose bugs. The absolute worst involves cases where there are sounds buried inside the timelines of the clips that fail to coerce. In Flash Player 9, it is entirely possible that if you were to call gotoAndStop(totalFrames) in your document class that you would see in your output window a message that every NewMovieClipX on every frame had instantiated, even though the timeline only “skimmed” across them. If these clips were to contain sound files on their timelines, you would hear these play in an infinite loop, and be left with no way to stop them selectively.

Tags: , , ,

  1. #1 written by Amy June 15th, 2012 at 04:53

    There’s a reason a good Actionscript programmer with a lot of experience would want to name instances of different types the same thing, and this is if you want to do something with the new instance (like populate it with data) and/or clean up the old instance (like removing listeners). The solution is to uncheck “declare stage instances automatically,” and declare the type yourself. Then you can use either an Interface for the type or a common base Class. I do believe you will get a warning if you use an Interface, possibly because Flash just isn’t that bright sometimes.