View comments | RSS feed

Packages

Packages in ActionScript 3.0 are implemented with namespaces, but are not synonymous with them. When you declare a package, you are implicitly creating a special type of namespace that is guaranteed to be known at compile time. Namespaces, when created explicitly, are not necessarily known at compile time.

The following example uses the package directive to create a simple package containing one class:

package samples
{
    public class SampleCode
    {
        public var sampleGreeting:String;
        public function sampleFunction()
        {
            trace(sampleGreeting + " from sampleFunction()");
        }
    }
}

The name of the class in this example is SampleCode. Because the class is inside the samples package, the compiler automatically qualifies the class name at compile time into its fully qualified name: samples.SampleCode. The compiler also qualifies the names of any properties or methods, so that sampleGreeting and sampleFunction() become samples.SampleCode.sampleGreeting and samples.SampleCode.sampleFunction(), respectively.

Many developers, especially those with Java programming backgrounds, may choose to place only classes at the top level of a package. ActionScript 3.0, however, supports not only classes at the top level of a package, but also variables, functions, and even statements. One advanced use of this feature is to define a namespace at the top level of a package so that it will be available to all classes in that package. Note, however, that only two access specifiers, public and internal, are allowed at the top level of a package. Unlike Java, which allows you to declare nested classes as private, ActionScript 3.0 supports neither nested nor private classes.

In many other ways, however, ActionScript 3.0 packages are similar to packages in the Java programming language. As you can see in the previous example, fully qualified package references are expressed using the dot operator (.), just as they are in Java. You can use packages to organize your code into an intuitive hierarchical structure for use by other programmers. This facilitates code sharing by allowing you to create your own package to share with others, and to use packages created by others in your code.

The use of packages also helps to ensure that the identifier names that you use are unique and do not conflict with other identifier names. In fact, some would argue that this is the primary benefit of packages. For example, two programmers who wish to share their code with each other may have each created a class called SampleCode. Without packages, this would create a name conflict, and the only resolution would be to rename one of the classes. With packages, however, the name conflict is easily avoided by placing one, or preferably both, of the classes in packages with unique names.

You can also include embedded dots in your package name to create nested packages. This allows you to create a hierarchical organization of packages. A good example of this is the flash.xml package provided by the Flash Player API. The flash.xml package is nested inside the flash package.

The flash.xml package contains the legacy XML parser that was used in previous versions of ActionScript. One reason that it now resides in the flash.xml package is that the name of the legacy XML class conflicts with the name of the new XML class that implements the XML for ECMAScript (E4X) specification functionality available in ActionScript 3.0.

Although moving the legacy XML class into a package is a good first step, most users of the legacy XML classes will import the flash.xml package, which will generate the same name conflict unless you remember to always use the fully qualified name of the legacy XML class (flash.xml.XML). To avoid this situation, the legacy XML class is now named XMLDocument, as the following example shows:

package flash.xml
{
    class XMLDocument {}
    class XMLNode {}
    class XMLSocket {}
}

Most of the Flash Player API is organized under the flash package. For example, the flash.display package contains the display list API, and the flash.events package contains the new event model.

Creating packages

ActionScript 3.0 provides significant flexibility in the way you organize your packages, classes, and source files. Previous versions of ActionScript allowed only one class per source file and required that the name of the source file match the name of the class. ActionScript 3.0 allows you to include multiple classes in one source file, but only one class in each file can be made available to code that is external to that file. In other words, only one class in each file can be declared inside a package declaration. You must declare any additional classes outside your package definition, which makes those classes invisible to code outside that source file. The name of the class declared inside the package definition must match the name of the source file.

ActionScript 3.0 also provides more flexibility in the way you declare packages. In previous versions of ActionScript, packages merely represented directories in which you placed source files, and you didn't declare packages with the package statement, but rather included the package name as part of the fully qualified class name in your class declaration. Although packages still represent directories in ActionScript 3.0, packages can contain more than just classes. In ActionScript 3.0, you use the package statement to declare a package, which means that you can also declare variables, functions, and namespaces at the top level of a package. You can even include executable statements at the top level of a package. If you do declare variables, functions, or namespaces at the top level of a package, the only attributes available at that level are public and internal, and only one package-level declaration per file can use the public attribute, whether that declaration is a class, variable, function, or namespace.

Packages are useful for organizing your code and for preventing name conflicts. You should not confuse the concept of packages with the unrelated concept of class inheritance. Two classes that reside in the same package will have a namespace in common, but are not necessarily related to each other in any other way. Likewise, a nested package may have no semantic relationship to its parent package.

Importing packages

If you want to use a class that is inside a package, you must import either the package or the specific class. This differs from ActionScript 2.0, where importing classes was optional.

For example, consider the SampleCode class example from earlier in this chapter. If the class resides in a package named samples, you must use one of the following import statements before using the SampleCode class:

import samples.*;

or

import samples.SampleCode;

In general, import statements should be as specific as possible. If you plan to use only the SampleCode class from the samples package, you should import only the SampleCode class rather than the entire package to which it belongs. Importing entire packages may lead to unexpected name conflicts.

You must also place the source code that defines the package or class within your classpath. The classpath is a user-defined list of local directory paths that determines where the compiler will search for imported packages and classes. The classpath is sometimes called the build path or source path.

After you have properly imported the class or package, you can use either the fully qualified name of the class (samples.SampleCode) or merely the class name by itself (SampleCode).

Fully qualified names are useful when identically named classes, methods, or properties result in ambiguous code, but can be difficult to manage if used for all identifiers. For example, the use of the fully qualified name results in verbose code when you instantiate a SampleCode class instance:

var mySample:samples.SampleCode = new samples.SampleCode();

As the levels of nested packages increase, the readability of your code decreases. In situations where you are confident that ambiguous identifiers will not be a problem, you can make your code easier to read by using simple identifiers. For example, instantiating a new instance of the SampleCode class is much less verbose if you use only the class identifier:

var mySample:SampleCode = new SampleCode();

If you attempt to use identifier names without first importing the appropriate package or class, the compiler will not be able to find the class definitions. On the other hand, if you do import a package or class, any attempt to define a name that conflicts with an imported name will generate an error.

When a package is created, the default access specifier for all members of that package is internal, which means that, by default, package members are only visible to other members of that package. If you want a class to be available to code outside the package, you must declare that class to be public. For example, the following package contains two classes, SampleCode and CodeFormatter:

// SampleCode.as file
package samples
{
    public class SampleCode {}
}

// CodeFormatter.as file
package samples
{
    class CodeFormatter {}
}

The SampleCode class is visible outside the package because it is declared as a public class. The CodeFormatter class, however, is visible only within the samples package itself. If you attempt to access the CodeFormatter class outside the samples package, you will generate an error, as the following example shows:

import samples.SampleCode;
import samples.CodeFormatter;
var mySample:SampleCode = new SampleCode(); // okay, public class
var myFormatter:CodeFormatter = new CodeFormatter(); // error

If you want both classes to be available outside the package, you must declare both classes to be public. You cannot apply the public attribute to the package declaration.

Fully qualified names are useful for resolving name conflicts that may occur when using packages. Such a scenario may arise if you import two packages that define classes with the same identifier. For example, consider the following package, which also has a class named SampleCode:

package langref.samples
{
    public class SampleCode {}
}

If you import both classes, as follows, you will have a name conflict when referring to the SampleCode class:

import samples.SampleCode;
import langref.samples.SampleCode;
var mySample:SampleCode = new SampleCode(); // name conflict

The compiler has no way of knowing which SampleCode class to use. To resolve this conflict, you must use the fully qualified name of each class, as follows:

var sample1:samples.SampleCode = new samples.SampleCode();
var sample2:langref.samples.SampleCode = new langref.samples.SampleCode();

NOTE

 

Programmers with a C++ background often confuse the import statement with #include. The #include directive is necessary in C++ because C++ compilers process one file at a time, and will not look in other files for class definitions unless a header file is explicitly included. ActionScript 3.0 has an include directive, but it is not designed to import classes and packages. To import classes or packages in ActionScript 3.0, you must use the import statement and place the source file that contains the package in the class path.


Flash CS3


Comments


mgoodes said on Sep 29, 2007 at 7:35 PM :
Hmm...I've read this twice now, and amidst all the extraneous information I cannot find the things I really need to know:
- How do I name/organize my files and folders so that AS 3.0 can find them
- How do I name my packages/classes to avoid compile errors
- Where do I write the "new" statement - is it even possible to write a "new" statement in a frame without getting a compile time error?
I'm sure all the Java programmers are happy with this documentation but as an AS programmer I'm stuck using frame code because I can't get my packages and classes to compile.
djtechwriter said on Oct 1, 2007 at 10:42 AM :
mgoodes,

You're asking about several different documentation issues. So, in the order you asked:

- This page in Using Flash should help:
http://livedocs.adobe.com/flash/9.0/UsingFlash/WS06D23361-54E6-4ac2-9D24-081C181BD2DF.html

Keep in mind that AS3 classes and packages are compiled by the authoring tool (in this case, Flash CS3, not FlexBuilder). So, the information you want is in the Using Flash book.

- Name them what you want, basically. Look through the AS3 Language Reference and don't name them the same as the ones included with Flash CS3. For simplicity, you can put all your classes at the "top level" as stated above. The names shouldn't spawn a compiler error unless your syntax is incorrect. It doesn't have anything to do with the names you use. This page may help:
http://livedocs.adobe.com/flash/9.0/main/00000028.html

- The new operator is documented here:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/operators.html#new
No screen name said on Jan 8, 2008 at 3:07 AM :
I'm a relative newcomer to Flash but if anyone's having trouble getting packages and package names working, you could do a lot worse than check out this tutorial: http://www.actionscript.org/resources/articles/698/1/Make-your-own-reusable-classes-using-Flash-and-AS3/Page1.html
tegnegi said on Feb 23, 2008 at 10:55 AM :
I ve read the whole section but still can't get that packages can be created
that does not reflect directory hierarchy. Could you please suggest some example code.
No screen name said on Mar 24, 2008 at 12:05 PM :
Hello, another somewhat confused user here...

I think I understand now. I'll give an example of my code, my conclusion from it, and my reflections on what that means:

I have the following file structure:

package/
package.as
Class.as

my intention was to have simple service functions in package.as that will be accessed via package.function(). for example package.initialize().

However, I kept getting compiler errors. I eventually tracked it down to this: you can only declare one public thing in a package - class, function whatever, and that something's name must correspond to the package name.

So I stopped getting compiler errors when I change my files and code like so:

package/
initialize.as - contains package.initialize()
Class.as - contains package.Class

At this point things started working.

However, you must realize this is less than desired. I don't want to be forced to breakdown a library of 10 small utility functions to 10 files. I could of course use static methods on a class, but that beats the whole point of using packages.
peterevensen said on Apr 3, 2008 at 8:51 AM :
What isn't explicitly explained here (but is in the AS 2.0 documentation) is that:

1) Each package class has to be in it's own .as file and that file must be named after the one public class contained in that file (e.g., MyClass.as).

2) The .as files for each class in a package must be stored in a folder that matches the package name.

3) The folder containing the package folder must be in the ClassPath (either global or local).

This information is covered in Programming ActionScript 2.0, but not really explained here (and so easily missed by someone new to ActionScript who starts with AS3).
unasuming_dave said on Apr 30, 2008 at 3:27 PM :
In the "Creating packages" section it states "If you do declare variables, functions, or namespaces at the top level of a package, the only attributes available at that level are public and internal, and only one package-level declaration per file can use the public attribute, whether that declaration is a class, variable, function, or namespace."

Actually it seems that only one package-level declaration can be made at all, whether public or internal

 

RSS feed | Send me an e-mail when comments are added to this page | Comment Report

Current page: http://livedocs.adobe.com/flash/9.0/main/00000041.html