[AS2 OOP] Why do classes of nested MCs not construct immediately?

[FONT=Arial]Hi everyone. I’ve gotten a lot of good help here so far and hope to return the favour someday.[/FONT]

[FONT=Arial]I’m an intermediate AS2 coder starting to use better OOP practices. I have searched for the answer to this but have not found anything, perhaps because everyone else learned it a long time ago.[/FONT]

[FONT=Arial]It appears that classes which extend an MC which is contained inside a different MC do not run their constructor immediately after the containing MC is instantiated. Also this MC’s methods are not immediately available. As a result I need to wait a bit, by using onLoad or another frame. I can live with it but it feels kludgy.[/FONT]

[FONT=Arial]Here is an illustration which I have made as slim as possible:[/FONT]

[FONT=Arial]–Symbol with ID “ball”, linked to AS2 class “Ball”.[/FONT]

[FONT=Arial]–Symbol with ID “box”, linked to AS2 class “Box”. This symbol contains an instance of “ball” which I dragged in there and gave an instance name “ball_0”.[/FONT]

[FONT=Arial]–Symbol with ID “launcher”, linked to AS2 class “Launcher”.[/FONT]

[FONT=Arial]–Dragged onto stage’s frame 1 the symbol “launcher”.[/FONT]

[FONT=Arial]–Nothing else on stage.[/FONT]


dynamic class Launcher extends MovieClip {
	function Launcher() {
		trace("Launcher constructor");
	function init(Void) {
		instance = this.attachMovie("box", "box_0", 0);
		trace("Box has been attached");
		trace("The ball's _x is: "+instance.ball_0._x);
		trace("Setting A directly");
		instance.ball_0.testPropA = "Launcher init() put this here";
		trace("Ball testPropA is: "+instance.ball_0.testPropA);
		trace("Setting B with method, immediately");
		trace("Ball testPropB is: "+instance.ball_0.testPropB);
dynamic class Box extends MovieClip {
	function Box() {
		trace("Box constructor");
dynamic class Ball extends MovieClip {
	function Ball() {
		trace("Ball constructor");
	function setB(Void) {
		trace("Running setB");
		this.testPropB = "Ball setB() put this here"
	function onLoad(Void) {
		trace("Ball onLoad");
		trace("Setting B with method after onLoad");
		trace("Now ball testPropB is: "+this.testPropB);

[FONT=Arial]Launcher constructor[/FONT]
[FONT=Arial]Box constructor[/FONT]
[FONT=Arial]Box has been attached[/FONT]
[FONT=Arial]The ball’s _x is: 68.55[/FONT]
[FONT=Arial]Setting A directly[/FONT]
[FONT=Arial]Ball testPropA is: Launcher init() put this here[/FONT]
[FONT=Arial]Setting B with method, immediately[/FONT]
[FONT=Arial]Ball testPropB is: undefined <----------------------problem is here[/FONT]
[FONT=Arial]Ball constructor[/FONT]
[FONT=Arial]Ball onLoad[/FONT]
[FONT=Arial]Setting B with method after onLoad[/FONT]
[FONT=Arial]Running setB[/FONT]
[FONT=Arial]Now ball testPropB is: Ball setB() put this here[/FONT]

[FONT=Arial]See the ball in the box, as expected.[/FONT]

[FONT=Arial]If I comment out the init() in Launcher’s constructor and instead put into frame1 this code, I get the same result:[/FONT]

[FONT=Arial]How can I fix this so that setB would work in the above example? I have found two workarounds but I wonder if there is another which feels less kludgy.[/FONT]

[FONT=Arial]Solution A): As seen in the example, put into Ball an onLoad function (or maybe just its constructor) which then runs any initialization functions. As a result I need to store in the object some properties which the object can find in itself and use for initialization.[/FONT]

[FONT=Arial]Solution B): Put the method call on a timeline frame after the frame in which the attachMovie is done.[/FONT]

[FONT=Arial]At the heart of this question is, why can I set the ball’s properties (as seen with setA) but not be able to call its methods successfully? On one hand, I can see that the thread is busy with the box’s initialization and can’t be expected to run ball’s constructor right away, even though ball has been instanced. But on the other hand, I am actually calling a method of an instance which is obviously there, so shouldn’t it have the common decency to do as I ask? ;)[/FONT]

[FONT=Arial]Bonus question is, is the fact that this does not work a bug in Flash AS2 or is it perfectly to be expected due to some CS common sense which I lack?[/FONT]

[FONT=Arial]Another bonus question is, is this a harebrained way to use Flash AS2 classes—linking symbols to AS2 classes which extend MovieClip (or which are subclasses of classes which themselves extend MovieClip), and using attachMovie to instance all of these MCs except the one “Launcher” which is the only thing on the .fla’s stage? It’s a cornerstone of my architecture so I’d like to know if this is utterly daft.[/FONT]

[FONT=Arial]Thanks very much for any enlightenment.[/FONT]

Would you mind posting a ZIP with the class files and an FLA?

By request here are the files… forgot I could attach 'em here.

Still curious as to any thoughts here.

By the way, in Ball.as I took everything from onLoad, put it in the constructor, and got the same result. I expected the undefined to still result, and was pleased to see that setB did work when it was called in the constructor. The output was exactly the same as when I used onLoad.

However in many posts I have been seeing sinister pronouncements of the type “don’t trust the constructor, there are problems with using it”. Can anyone point me to more detail on when to use and not use the constructor? And if using onLoad is more reliable?

(But still mainly looking for a response to my original questions so I can be more confident in my architecture plans)

onLoad is the correct route. If you want to interact with class-associated movie clips nested within other movie clips, you will need to wait until the parent movie clips have “loaded” (indicated by the onLoad event) before complete instantiation with class association has completed.

Yes, instances will exist prior to full instantiation, as you could see by accessing the _x property of ball, however, you’ll also noticed that the ball constructor has yet to run meaning that there has been no association with the class in which it has been… associated… with. Until that happens, you will not have access to that instance’s class-inherited methods. When you know that has happened is through a parent movie clip’s onLoad event.

Keep in mind that onLoad events only fire for movie clips associated with classes and where onLoad is defined within the class definition (even if empty and to be redefined after parent class instantiation).

For your case, using launcher as you are, I would suspect the direction you would want to go is to have an empty onLoad defined in Box that you can override in Launcher and have that call setB for Ball once it has completed full instantiation.

Thanks, senocular! I’ll go with onLoad. It will probably be a better habit as it forces me to make the object self-init by drawing from its own properties instead of having a sequence of calls from the outside do the init.