|
Creating and using an mx_internal style Namespace A guide for creating and using a Framework-Internal Namespace Published Fri, Oct 26, 2007 at 9:31 PM Ever wonder how to create a Namespace like mx_internal? I found that most Namespace documentation is geared towards name spacing XML, so I thought it would be a good idea to write a bit about this topic in order to create some related online resources. At this time, the only online information I could find that dealt specifically with the keyword namespace was the Statements, Keywords & Directives document. This document describes how to create and use a Namespace, but leaves it up to you to figure out the context it can be used in, or even its limits. I wanted to be able to define a Namespace accessible by any Class in any package, and I think I can best illustrate how to do that by sharing the thought process which led me to my conclusions. This article will mostly describe what not to do, but nonetheless, hopefully along the way we'll figure out how to create and use a Namespace. I've also included an example to illustrate the code structure. Okay, so I guess it's pretty straight forward to assume that a package level Namespace would somehow need to be defined on the package level. I simply wanted to test if this was true so I jammed a Namespace definition straight into the package level of a Class file - just as any professional programmer would do: package package_a {
namespace ns_example;
public class A {
}
} About that time I was faced with a compile time error: "A file found in a source-path cannot have more than one externally visible definition." Lovely. From here we find out that package level Namespace declarations are handled like Class declarations in that multiple Classes/Namespaces cannot be defined in one .as file. We can accept that it contains some characteristics of a Class declaration, but it certainly makes one question the underlying concept that relates these entities. It seems a safe assumption to think that package level declarations should share certain characteristics, and as usual, the compiler and I agreed that since a file name and Class name must match, it would only make sense to disallow multiple package level definitions in one file. I figured the same should apply for defining anything else for a package as it better avoids semantic confusion. So moving forward, I went ahead and created a file called ns_example.as: //located in ns_package/ns_example.as package ns_package {
namespace ns_example;
} After importing my Namespace as I would mx_internal, I quickly hit ctrl+b to compile my code, but much to my dismay, I faced yet another compile time error: "Namespace was not found or is not a compile-time constant." There was just one way I could recover from an error with a severity level of 1004. I quickly opened the mx library source and located the mx_internal.as file. "Well well well," I thought to myself, "What do we have here? mx_internal is declared... public?" I didn't realize that I would have to scope my scope (Namespace). We declare Namespaces just like we declare Classes, and the default scope for both is internal, except the compiler doesn't warn you about this for Namespaces. You can even use the dynamic keyword with a Namespace declaration, and to be quite honest, I don't know why since the keyword doesn't appear to affect the way Objects are allowed to interact with the Namespace. Moving forward, I hit ctrl+b after scoping my Namespace to public. So far so good, no compile time errors. Once I declared some members with my new Namespace, I set up some code to access it from the application object. I launched a test in debug mode and saw my trace function print my ns_example variable. I always knew my trace function would someday print amazing things. What a champ. Now to sum it up, you'll want to start by creating your Namespace: //located in ns_package/ns_example.as package ns_package {
public namespace ns_example = "http://www.example.com/ns/example";
} You now must import it before defining or accessing Class members with it: import ns_package.ns_example; You don't have to import it if the Class and Namespace is in the same package, but I encourage using internal to scope your members unless the Namespace is used outside of the package. From a design point of view, it may make sense to use a Namespace for a framework or a component set within one package, but it may not always make sense to create such a collection of classes in just one package, so you might be better off using the internal Namespace if the Namespace isn't used outside of the package. Functionally the internal Namespace is practically the package Namespace. You can use the 'use namespace' directive to qualify members. This way you can access members without having to repeatedly qualify them. For example, to access the example property of a, we can use the :: operator to qualify the property: import ns_package.ns_example; trace(a.ns_example::example); Or you can use the 'use namespace' directive to qualify all members within a particular scope: import ns_package.ns_example; use namespace ns_example; trace(a.example); You can download the code I've created to illustrate the structure of declaring and using a package level Namespace. I hope this has helped those of you who have been curious about Namespaces. Any further curiosity should prime you to attend to Essential ActionScript 3 by Collin Moock. Check out the section called Namespace. |