This blog has moved to a new location! http://iqandreas.github.com/

Friday, April 10, 2009

Understanding the AS3 "1203 No default constructor found in base class %s. " Error

Gather 'round children, and I will describe to you the 1203 error in child friendly Layman's Terms.

"1203 No default constructor found in base class %s.
You must explicitly call the constructor of the base class with a super() statement if it has 1 or more required arguments."



When you extend a class in AS3, flash will automatically add a function that initializes the class that you are extending.

For example, let's say you have a "ship" class. When you create this class, you have a whole bunch of functions that create walls, shields, passenger compartments, motors, etc.

ActionScript Code:
public class Ship
{
public function Ship():void
{
//Here you will build the ship, and make sure it is functional.
this.buildHullAndWalls();
this.buildPassengerCompartments();
this.addElectronics();
this.addNavigation();
this.addMotors(new HyperDrive(), new SublightEngine());
this.addSheilds();

if (this.scanForDefects())
{
emailCaptain("Ship is in working order and ready to go! :) ");
}
else
{
emailCaptain("There is something wrong! There are problems with this ship still!");
throw new ShipBuildError("An error occured when building the ship. Please wait for repairs.");
}
}

}



Now, when you want to extend a class, it is like creating a new version of the parent class AND adding to it.

So to create a Cruiser (basically a basic ship with weapons), you could write all this out:
ActionScript Code:
public class Cruiser
{
public function Cruiser():void
{
//Here you will build the ship, and make sure it is functional.
this.buildHullAndWalls();
...
this.addSheilds();
this.addWeapons();

if (this.scanForDefects())
{
...
}
}

}


But doing this for each and every ship that extends the Ship is long, tedious, and memory consuming. Also, if you want to make any changes to the way the ship works (for example, adding the shields before you add the motors), you have to go back and change that code in every single ship that is built from a Ship, or extends the Ship.

So to have the Cruiser extend Ship:
ActionScript Code:
public class Cruiser extends Ship
{
public function Cruiser():void
{
this.addWeapons();
}
}



This simplifies making ships immensely, however, we have one (major) problem. Here, you are telling the crew to start adding weapons to the ship. That's fine and dandy, but where is the ship? You haven't told the crew to start building a ship yet! How are they supposed to add on the weapons?

Luckily, The Flash Compiler (known to his friends as "Foreman Flash") realizes this, so when you tell the crew to start building the ship, Flash looks through the list of tasks for the crew to do. He realizes that you are technically building a ship, and since the builders can't add anything to the ship until the ship is built, he adds a task for the builders at the start of the list. He tells them "First, build a standard ship, like the one you made for Larry last month. Then, add weapons to it, and make it a cruiser instead."

ActionScript Code:
public class Cruiser extends Ship
{
public function Cruiser():void
{
super(); //This means, do everything that the super class (or Ship) does to start out.
this.addWeapons(); //Now you can add weapons when you have a ship built!
}
}



That's OOP 101. However, sometimes things get a little more complicated than that. What if in order to build the standard Ship, the builders have to know how many passengers it will hold. Otherwise, they don't know if they should build a little or a small ship.
ActionScript Code:
public class Ship
{
public function Ship(howManyPassengers:Number):void
{
//Here you will build the ship, and make sure it is functional.
this.buildHullAndWalls();
this.buildPassengerCompartments(howManyPassengers);
this.addElectronics();
this.addNavigation();
this.addMotors(new HyperDrive(), new SublightEngine());
this.addSheilds();

if (this.scanForDefects())
{
...
}
}

}



Now we run into a problem. Foreman Flash has the task of building another Cruiser. As usual, he looks through the list to check if the ship can be built, so cruiser weapons can be added to it. Realizing that someone forgot that command, he again adds super() to the list, and the builders start working.

The builders start gathering supplies, when one person calls out "Wait a minute! How big is this ship supposed to be? Foreman Flash, we do not know how many passengers this thing will hold!"

Foreman flash looks at his clipboard again and again, but he has no idea of how big the client wanted the cruiser. He is now confused, and the builders are getting angry. Guessing a random numbe could be disasterous.

"1203 No default constructor found in base class! Help! I'm confused! No one ever told me what to do! I can't build without proper instructions!"

There is your error.


Next time, the ship buying millionare is smarter. When he orders a Cruiser, he says "I want the ship to hold 24,000 passengers. Get it done right this time."

ActionScript Code:
//This code is run elsewhere, perhaps on the main timeline
var NumberOfPassengersForMyCruiser:Number = 24000;
var MyPimpedOutCruiser:Cruiser = new Cruiser(NumberOfPassengersForMyCruiser);

//Here is the actual class located elsewhere.
public class Cruiser extends Ship
{
public function Cruiser(passengers:Number):void
{
super(passengers); //Now we add building the ship to the list so the Foreman doesn't have to worry about adding it himself.
this.addWeapons(); //Now you can add weapons, because the builders know how big the ship will be!
}
}



Another way of doing this, is perhaps there is a law in place which states that all cruisers must be built for 40,000 passengers. No more, no less.
ActionScript Code:
public class Cruiser extends Ship
{
public function Cruiser():void
{
super(40000); //Because the super() command just won't suffice!
this.addWeapons(); //Now you can add weapons, because the builders know how big the ship will be!
}
}



Or, if you are really smart, you could change the plans of the Ship design to say that, unless you hear anything differently, the ship will always be built for 30,000 passengers.

ActionScript Code:
public class Ship
{
public function Ship(howManyPassengers:Number = 30000):void
{
//Here you will build the ship, and make sure it is functional.
this.buildHullAndWalls();
this.buildPassengerCompartments(howManyPassengers);
this.addElectronics();
this.addNavigation();
this.addMotors(new HyperDrive(), new SublightEngine());
this.addSheilds();

if (this.scanForDefects())
{
...
}
}

}


Now the Cruiser class can look like this:
ActionScript Code:
public class Cruiser extends Ship
{
public function Cruiser(passengers:Number):void
{
//Don't bother adding the super() command here. The Foreman will do it automatically. That's what he's getting paid for. :)
//You can add it if you want to, but I say it is a waste of your time.
this.addWeapons();
}
}


When the Foreman looks through the list, he sees that you never told the workers start building the ship. "No problem, I'll just add the super() command here."

Then the builders receive their instructions. "First, build a ship, then add weapons to it. Wait! The foreman never told us how many passengers he want the ship to hold. Oh well, by default, they want 30,000 passengers, so we will just do what we usually do."

No errors. Everyone is happy.



Now. To go back to your code...
ActionScript Code:
package
{
import com.RadarPoint;
public class Rp1 extends RadarPoint
{
function Rp1():void
{
trace("YEAY! New RadarPoint child RP1 created!");
}
}
}


The Foreman looks through this code, and sees that you are building a RadarPoint, but you never told the workers to start building the RadarPoint! Proposterous! He quckly adds it to the list and send the workers on their way.

ActionScript Code:
import com.RadarPoint;
public class Rp1 extends RadarPoint
{
function Rp1():void
{
super(); //Added by the foreman.
trace("YEAY! New RadarPoint child RP1 created!");
}
}


So the workers look at the list, and start building a Radar Point. "Woah!! Big problem!! Foreman!!! We don't know what the values of newProp1:int, newProp2:Number, and newProp3:String are supposed to be!!"

ActionScript Code:
import flash.display.Sprite;
public class RadarPoint extends Sprite
{
function RadarPoint(newProp1:int, newProp2:Number, newProp3:String):void
{
this._prop1 = newProp1;
this._prop2 = newProp2;
this._prop3 = newProp3;
}
}



Next time, when the millinaire is ordering his brand new RP1, he remembers to tell the foreman and the builders what specifications he wants, avoiding any confusion:
ActionScript Code:
package
{
import com.RadarPoint;
public class Rp1 extends RadarPoint
{
function Rp1():void
{
super(3467, -345.37327, "Red/Blue");
trace("YEAY! New RadarPoint child RP1 created!");
}
}
}


Moral of the story, always tell Foreman Flash what to do, otherwise he gets mad and thows errors and swearwords in your way.



I should win a Pulizer.

15 comments:

  1. Awsome explanation, thanks!

    ReplyDelete
  2. Whoo! that solved my problem! now I understand Foreman Flash much better

    ReplyDelete
  3. Glad I could help. :)

    Hopefully, if I can get some more free time, I will post some more tutorials in a similar style (and hopefully the same characters)

    Even though my teaching methods are bizarre, I tend to remember easier when learning in this way.

    Is there anything out there you (meaning all of you reading) would like to understand better?

    Good luck with your action scripting,
    Andreas

    ReplyDelete
  4. Hey Andreas,

    First let me say that its an awesome entry (I found it on the kirupa forums first). I'm personally from a devloper background so I understand most of the OOP-ness in this.

    However I have a question which stems from this sort of a setup (1 class, many library assets). Since I set the linkage in the Flash IDE to create a dynamic class for each asset (rp1 rp2 etc) and the base class as my own class (RadarPoint in this case), is there a way I can access children of the Derived class movie clips in the Base class?

    So say on stage every radar point has a sub movie clip with an instance name of 'center', which does something funky (doSomethingFunky()). So I write the method doSomethingFunky() in RadarPoint class, however I can't reference 'this.center' in methods in RadarPoint. Any ideas?

    ReplyDelete
  5. All I can say is: Super! Thank you for this post.

    p.s. Forman Flash rules! :D

    ReplyDelete
  6. there's HTML glitches all over this post where you're attempting to set the color in HTML, e.g.:
    `color="SeaGreen"`

    But, I understand the concept, now regardless. Thanks!

    ReplyDelete
  7. For the replies, better late than never. :(

    @pupco
    Thanks for pointing that out. :) Problem finally fixed.

    @Archit
    If I understand you correctly, each child class that extends "RadarPoint" will have a MovieClip inside of it named "center".

    The problem is that the "RadarPoint" class has no way of knowing or guaranteeing that all children will always contain a child named "center", so it's a bad idea to try to reference that MovieClip from inside of the RadarPoint class.

    However, there are three workarounds off the top of my head:

    ACCESS THE CENTER MC USING A STRING
    To access and move the center MovieClip 10 pixels to the right:
    this["center"].x += 10;
    This will cause errors if there is no MovieClip with an instance name of "center".

    CREATE A REFERENCE (SHORTCUT) TO THE CENTER MC
    This code is placed inside of the class, but outside of any functions so it can be accessed publicly (or you can make it private if you only want 'center' to be able to be accessed inside of the RadarPoint class):
    public var center:MovieClip;
    This code is best placed in the constructor or somewhere where it is accessed directly:
    this.center = centerInstance;
    OR
    this.center = this.getChildByName("centerInstance");
    This idea isn't a real good one either just in case the "child classes" don't contain a MovieClip named "centerInstance".

    ADD THE CENTER MC BY CODE
    This is always the best way, but might be a little tricky for beginners:
    var cmc1:CenterMC = new CenterMC;
    this.addChild(cmc1);
    cmc1.x = this.width / 2;
    cmc1.y = this.height / 2;


    Does that clarify it for you?

    ReplyDelete
  8. Damn That Foreman is a complicated guy..I bet he has no friends

    ReplyDelete
  9. Fantastic!
    Love how you've explained the whole 'super()'-stuff in such a great and understanding way! You should write a book :).

    ReplyDelete
  10. this is a very good post. Thanks a lot. Your way of writing is great to remember things :)

    ReplyDelete
  11. I never understood Super()untill now, just used it like an idiot.

    A super() thank you !

    ReplyDelete
  12. Great explanation, next time that i'll be also explaining something in actionscript, mr Foreman flash will also be there !

    Many thanks !

    ReplyDelete
  13. This is awesome! Best explanation on super/error 1203. I agree you should def. write a book! Thanks.

    ReplyDelete
  14. Having a problem with importing Library Items.

    Screen(id:String)
    this extends Sprite

    ScreenTitle()
    this extends Screen
    it calls, super("title") on construct

    ScreenManager()
    you can call addScreen(scr:Screen) to store them

    In my library I have a movieclip, ScreenTitle, in the Linkage Properties it's Class is defined as: ScreenTitle and Base Class as Sprite

    I call this code:

    var screenTitle:ScreenTitle = new ScreenTitle();
    screenManager.addScreen(screenTitle);

    I get this error:

    1067: Implicit coercion of a value of type ScreenTitle to an unrelated type com.*****.framework:Screen.

    --

    Any idea what is going wrong. It doesn't seem to recognise that it is subclassing Screen anymore.

    Please email me via contact on my site if you can help.

    Cheers and thanks for the tutorial, it's helpful.

    ReplyDelete
  15. Hello Luke. :)

    "in the Linkage Properties it's Class is defined as: ScreenTitle and Base Class as Sprite"
    Try leaving the "Base Class" filed blank, or write "com.[whatever].fraemwork.Screen" in that field.

    The way it is right now, the library says to extend Sprite, while the ScreenTitle code wants to extend Screen. Which get's quite confusing for Foreman Flash. :)

    For future reference, I may not always be available, so feel free to ask your questions on the Kirupa forums and you may get a faster response (or any ActionScript forums that fit your linking for that matter)
    http://www.kirupa.com/forum/forumdisplay.php?f=141

    Good luck with your programming,
    Andreas

    ReplyDelete