Paul Robertson's words, punctuated

Thoughts on development, user-centered design, code, etc. by Paul Robertson

Multiple AS3 classes in one file

Several months ago I wrote a little something about compile-time and runtime error checking in ActionScript 3, borrowing from Bruce Eckels’ relatively well known example of “speaking pets.” In an attempt to be succinct and keep the code listings easy, I put all the class definitions within a single package (intended to be in a single .as document); the main class was public and the others were private, because of a compiler requirement that you could only have one public class per file. Unfortunately, I wrote the example using Flex Public Beta 2 (or maybe even Beta 1). In the subsequent betas and final release, a couple of changes rendered that code invalid:

  1. You are no longer allowed to use the private (or protected) access modifiers on class definitions.
  2. You are no longer allowed to define multiple classes within a package block in a single .as file – essentially, a single .as file will have one public class, and the file’s name must match the class name – which makes it easier for the compiler to find classes, I imagine.

Point 1, no more private or protected classes, seems to be pretty concrete (i.e. it’s part of the ActionScript 3.0 syntax). Frankly I don’t really mind this – the notion of a private class doesn’t really make sense (if it’s private, no other class can access it, after all). In the example I wrote, I used the private modifier because the compiler required it, in order for me to keep all the classes in a single .as document. I think when I first wrote the example, with public alpha 1, I used inner classes (classes defined inside other classes), but inner classes were removed from the syntax before the public betas were released.

Interestingly, point 2, that you can’t have multiple classes defined in a package block in a .as file, seems to be a limitation of the Flex compiler (that is, mxmlc) rather than a part of the syntax of ActionScript. First of all, as many people figured out, you can still have multiple classes defined in a .as file – you can just only include one of them in the package block, and the others must be defined outside the package, and cannot have any access modifier specified. Because they’re defined outside the package, these special classes are available to any class defined in the .as file, including the public class defined in the package block, but are not accessible to any other class. So you can still abstract out certain functionality to other classes, as you might do with a private inner class, but there’s just a difference in where it’s defined.

However, as I said, the rule about only having one public class per package block is (at least from what I can tell) only a limitation of the Flex compiler, not a part of ActionScript 3 syntax. Using the Flash 9 Public Alpha’s compiler, you can define a .as file with multiple classes defined in a single package block, and it compiles and runs just fine. You also don’t have the restriction that class names must match file names, or that files must be in a folder structure corresponding to their package structure. In fact, you can even have multiple package blocks in a single .as file, as long as the packages all appear before any classes defined outside of packages (I’m not sure if that’s a bug or intentional behavior).

Here is a file that demonstrates all of the variations that I have tried so far. Put the contents of this first listing in an external .as file – from what I can tell, the file’s name must match the name of one of the public classes it contains (e.g. I called my file “PubClass.as”).

package test
{
    public class PubClass
    {
        public function PubClass()
        {
            trace("PubClass constructor");
            var myExternalClass:ExternalClass = new ExternalClass();
            var myOtherPubClass:OtherPubClass = new OtherPubClass();
            var myInternalClass:InternalClass = new InternalClass();
        }
    }
    
    public class OtherPubClass
    {
        public function OtherPubClass()
        {
            trace("OtherPubClass constructor");
        }
    }
    
    internal class InternalClass
    {
        public function InternalClass()
        {
            trace("InternalClass constructor");
        }
    }
}

package package2
{
    public class Package2PubClass
    {
        public function Package2PubClass()
        {
            trace("Package2PubClass Constructor");
        }
    }
}

class ExternalClass
{
    public function ExternalClass()
    {
        trace("ExternalClass Constructor");
    }
}

I then put this code in the Actions panel on frame 1 of a FLA, in the same folder as the .as file:

import test.PubClass;
import test.OtherPubClass;
import package2.Package2PubClass;

var myPubClass:PubClass = new PubClass();
var myOtherPubClass:OtherPubClass = new OtherPubClass();
var myPackage2PubClass:Package2PubClass = new Package2PubClass();

The result looks like this:

PubClass constructor
ExternalClass Constructor
OtherPubClass constructor
InternalClass constructor
OtherPubClass constructor
Package2PubClass Constructor

Again, note that this code won’t work when compiled with the Flex compiler (e.g. using Flex Builder or the Flex Framework SDK). This only works with the Flash 9 ActionScript 3 Preview Public Alpha.

And now, for my opinion of this whole business…

Truth be known, I’m pretty sure I’ll still write all my classes in separate .as files. Why? To keep compatibility with Flex, and because I personally think it’s a better organization scheme. True, it sometimes seems a little silly to make a new .as file for a very small class, but later if that class grows, or even if it doesn’t, and you’re trying to find it, it will be much easier if it’s in its own .as file, and in a folder structure corresponding to its package. However, I know there are some people who want to be able to write multiple classes in a single .as file, and for instructional examples like the ones in the article I mentioned earlier, it’s convenient to be able to define multiple classes in a single document, so you can put them all in a code listing and just write “copy and paste all this code” rather than needing instructions about which code to place in which .as document.

Comments