Requirements

Prerequisite knowledge

You need to be familiar with variables, functions, objects, and packages in ActionScript 3.

User level

Beginning

When methods and properties are declared in ActionScript they can be declared with access modifiers such a public, private, protected and internal. These modifiers work quite well for a large number of cases; however, there are times when you need additional granularity. ActionScript solves this problem with a concept called namespace. In this article, you will learn what a namespace is and how to define one for use in your application. You will also learn to apply and reference namespace to control access to methods and properties.

A namespace is a set of unique names. You use namespaces to control the visibility of identifiers, such as property and method names. You create a namespace every time you create a package, but you can also explicitly define a namespace and apply it to code regardless of the code's package. Namespaces allow you to break out of the organization imposed by packages and overrule the limitations of access control attributes.

Defining namespaces

Namespaces contain one value, the Uniform Resource Identifier (URI), which is sometimes called the namespace name. A URI allows you to ensure that your namespace definition is unique.

You create a namespace by declaring a namespace definition in one of two ways. You can either define a namespace with an explicit URI or you can omit the URI. The following example shows how to define a namespace using a URI:

namespace flash_proxy = “http://www.adobe.com/flash/proxy”;

The URI serves as a unique identification string for that namespace. If you omit the URI, as in the following example, the compiler creates a unique internal identification string in place of the URI. You do not have access to this internal identification string.

namespace flash_proxy;

Once you define a namespace, with or without a URI, that namespace cannot be redefined in the same scope. An attempt to define a namespace that has been defined earlier in the same scope results in a compiler error.

If a namespace is defined within a package or a class, the namespace is not visible outside that package or class unless the appropriate access control specifier is used. For example, the following code shows the flash_proxy namespace defined within the flash.utils package. The lack of an access control attribute keyword means that the flash_proxy namespace is visible only to code within the flash.utils package:

package flash.utils {     namespace flash_proxy; }

The following code uses the public attribute to make the flash_proxy namespace visible to code outside the package:

package flash.utils{ public namespace flash_proxy; }

Applying namespaces

Applying a namespace means placing a definition into a namespace. Definitions that can be placed into namespaces include functions, variables, and constants (you cannot place a class into a custom namespace).

Consider, for example, a function declared using the public access control namespace. Using the public attribute in a function definition places the function into the public namespace, which makes the function available to all code. Once you have defined a namespace, you can use it the same way you would use the public attribute, and the definition is available to code that can reference your custom namespace. For example, if you define a namespace example1, you can add a method called myFunction() using example1 as an attribute, as the following example shows:

namespace example1; class someClass { example1 myFunction() {} }

Declaring the myFunction() method using the namespace example1 as an attribute means that the method belongs to the example1 namespace.

Keep in mind the following when applying namespaces:

  • You can apply only one namespace to each declaration.
  • There is no way to apply a namespace attribute to more than one definition at a time. If you want to apply your namespace to ten different functions, you must add your namespace as an attribute to each of the ten function definitions.
  • If you apply a namespace, you cannot also specify an access control specifier because namespaces and access control specifiers are mutually exclusive. In other words, you cannot declare a function or property as public , private , protected , or internal in addition to applying your namespace.

Referencing namespaces

You do not need to explicitly reference a namespace when you use a method or property declared with any of the access control attributes— public , private , protected , and internal —because the context controls access to these special namespaces. For example, definitions placed into the private namespace are automatically available to code within the same class. For namespaces that you define, however, such context sensitivity does not exist. To use a method or property that you have placed into a custom namespace, you must reference the namespace.

You can reference namespaces with the use namespace directive or you can qualify the name with the namespace using the name qualifier ( :: ) punctuator. Referencing a namespace with the use namespace directive "opens" the namespace, so that it can apply to any identifiers that are not qualified. For example, if you have defined the example1 namespace, you can access names in that namespace by using use namespace example1 :

use namespace example1; myFunction();

You can open more than one namespace at a time. Once you open a namespace with use namespace , it remains open throughout the block of code in which it was opened. There is no way to explicitly close a namespace.

Having more than one open namespace, however, increases the likelihood of name conflicts. If you prefer not to open a namespace, you can avoid the use namespace directive by qualifying the method or property name with the namespace and the name qualifier punctuator. For example, the following code shows how you can qualify the name myFunction() with the example1 namespace:

example1::myFunction();

Using namespaces

You can find a real-world example of a namespace that is used to prevent name conflicts in the flash.utils.Proxy class that is part of ActionScript 3. The Proxy class, which is the replacement for the Object.__resolve property from ActionScript 2, allows you to intercept references to undefined properties or methods before an error occurs. All of the methods of the Proxy class reside in the flash_proxy namespace to prevent name conflicts.

To better understand how the flash_proxy namespace is used, first understand how to use the Proxy class. The functionality of the Proxy class is available only to classes that inherit from it. In other words, if you want to use the methods of the Proxy class on an object, the object's class definition must extend the Proxy class. For example, if you want to intercept attempts to call an undefined method, extend the Proxy class and then override the callProperty() method of the Proxy class.

You may recall that implementing namespaces is usually a three-step process of defining, applying, and then referencing a namespace. Because you never explicitly call any of the Proxy class methods, however, the flash_proxy namespace is only defined and applied, but never referenced. ActionScript 3 defines the flash_proxy namespace and applies it in the Proxy class. Your code only needs to apply the flash_proxy namespace to classes that extend the Proxy class.

The flash_proxy namespace is defined in the flash.utils package in a manner similar to the following:

package flash.utils{ public namespace flash_proxy; }

The namespace is applied to the methods of the Proxy class as shown in the following excerpt from the Proxy class:

public class Proxy{ flash_proxy function callProperty(name:*, ... rest):* flash_proxy function deleteProperty(name:*):Boolean ... }

As the following code shows, first import both the Proxy class and the flash_proxy namespace. Then, declare your class such that it extends the Proxy class (you must also add the dynamic attribute if you are compiling in strict mode). When you override the callProperty() method, use the flash_proxy namespace.

package { import flash.utils.Proxy; import flash.utils.flash_proxy; dynamic class MyProxy extends Proxy { flash_proxy override function callProperty(name:*, ...rest):*{ trace("method call intercepted: " + name); } } }

If you create an instance of the MyProxy class and call an undefined method, such as the testing() method called in the following example, your Proxy object intercepts the method call and executes the statements inside the overridden callProperty() method (in this case, a simple trace() statement).

var mySample:MyProxy = new MyProxy(); mySample.testing(); // method call intercepted: testing

There are two advantages to having the methods of the Proxy class inside the flash_proxy namespace. First, having a separate namespace reduces clutter in the public interface of any class that extends the Proxy class. (There are about a dozen methods in the Proxy class that you can override, all of which are not designed to be called directly. Placing all of them in the public namespace could be confusing.) Second, use of the flash_proxy namespace avoids name conflicts in case your Proxy subclass contains instance methods with names that match any of the Proxy class methods. For example, you may want to name one of your own methods callProperty() . The following code is acceptable, because your version of the callProperty() method is in a different namespace:

dynamic class MyProxy extends Proxy { public function callProperty() {} flash_proxy override function callProperty(name:*, ...rest):*{ trace("method call intercepted: " + name); } }

Namespaces can also be helpful when you want to provide access to methods or properties in a way that cannot be accomplished with the four access control specifiers ( public , private , internal , and protected ). For example, you may have a few utility methods that are spread out across several packages. You want these methods available to all of your packages, but you don't want the methods to be public. To accomplish this, you can create a namespace and use it as your own special access control specifier.

The following example uses a user-defined namespace to group two functions that reside in different packages. By grouping them into the same namespace, you can make both functions visible to a class or package through a single use namespace statement.

This example uses four files to demonstrate the technique. All of the files must be within your classpath. The first file, myInternal.as, is used to define the myInternal namespace. Because the file is in a package named example, you must place the file into a folder named example. The namespace is marked as public so that it can be imported into other packages.

// myInternal.as in folder example package example { public namespace myInternal = "http://www.adobe.com/2006/actionscript/examples"; }

The second and third files, Utility.as and Helper.as, define the classes that contain methods that should be available to other packages. The Utility class is in the example.alpha package, which means that the file should be placed inside a folder named alpha that is a subfolder of the example folder. The Helper class is in the example.beta package, which means that the file should be placed inside a folder named beta that is also a subfolder of the example folder. Both of these packages, example.alpha and example.beta, must import the namespace before using it.

// Utility.as in the example/alpha folder package example.alpha { import example.myInternal; public class Utility { private static var _taskCounter:int = 0; public static function someTask(){ _taskCounter++; } myInternal static function get taskCounter():int { return _taskCounter; } } } // Helper.as in the example/beta folder package example.beta{ import example.myInternal; public class Helper { private static var _timeStamp:Date; public static function someTask() { _timeStamp = new Date(); } myInternal static function get lastCalled():Date { return _timeStamp; } } }

The fourth file, NamespaceUseCase.as, is the main application class, and should be a sibling to the example folder. In Flash Professional, this class would be used as the document class for the FLA. The NamespaceUseCase class also imports the myInternal namespace and uses it to call the two static methods that reside in the other packages. The example uses static methods only to simplify the code. Both static and instance methods can be placed in the myInternal namespace.

// NamespaceUseCase.as package { import flash.display.MovieClip; import example.myInternal; // import namespace import example.alpha.Utility;// import Utility class import example.beta.Helper;// import Helper class public class NamespaceUseCase extends MovieClip { public function NamespaceUseCase() { use namespace myInternal; Utility.someTask(); Utility.someTask(); trace(Utility.taskCounter); // 2 Helper.someTask(); trace(Helper.lastCalled); // [time someTask() was last called] } } }

Where to go from here

Namespaces allow a non-package- and non-inheritance-based way of controlling access to methods and properties of objects. They are widely used inside of larger ActionScript projects including component frameworks such as Adobe Flex. Namespaces are also used in conjunction with methods and properties. Learn more about these by reading Introduction to objects, Introduction to Classes, and Writing classes in ActionScript 3 (all coming October 31).

Acknowledgement

The content in this article is based on material originally published in the Learning ActionScript 3 user guide created by Adobe Community Help and Learning.