IntroductionOne of the most powerfull feature of the AS3 language and yet totally underused (to not say ignored). The definition given in the language specification is not very clear at first, so let's try to make it simpler. The idea of the namespaces got their origin from XML namespaces, but really we don't care about that. The basic principle of those namespaces is to allow you to define your own attribute statements. what ? You do know those basic little things like public, private, protected ? in short defining your own namespace allow you to define your own protected attribute keyword, Yeah it's a bit magic like that. To put it another way, if you define a namespace hello And you can create as many namespaces as you want. DetailsThe problem with namespaces is there are not that obvious to use, but no worries here some examples and tips. The thing to remember mainly is if with public, private, protected basic usageLet's say you have a basic class with a method that you want to do different things wether you're in debug or release mode. package test
{
public class ClassA
{
public function ClassA()
{
}
public function debugTest( msg:String ):void
{
trace( "debug: " + msg );
}
public function releaseTest( msg:String ):void
{
trace( "release: " + msg );
}
}
}not very sexy or usable like that, you just want to use test in either one context or another first define your namespaces package test
{
public namespace debug;
}package test
{
public namespace release;
}and now use them in your class package test
{
public class ClassA
{
public function ClassA()
{
}
debug function test( msg:String ):void
{
trace( "debug: " + msg );
}
release function test( msg:String ):void
{
trace( "release: " + msg );
}
}
}yes you just have 2 methods named the same, and yes you just replaced your public attributes now let's use this import test.ClassA;
var a:ClassA = new ClassA();
a.test( "hello world" );not gonna work, the compiler probably gonna tell you he can not find the test method. When you declare something public, this attribute is open by default by the language, You have to explicitly tell that you want to use your namespace, and for that there is 2 way of doing it you directly provide the path of the namespace import test.ClassA;
import test.debug; //yes you have to import your namespace for it to be visible
var a:ClassA = new ClassA();
a.debug::test( "hello world" ); //full path to the namespace containing your method
//will trace "debug: hello world"or even better, you explicitly tell the language you want to use the namespace import test.ClassA;
import test.debug;
use namespace debug; //hey I want to use the namespace debug
var a:ClassA = new ClassA();
a.test( "hello world" ); // and now you can directly access the method
//will trace "debug: hello world"and off course, you can switch between namespaces import test.ClassA;
import test.release;
use namespace release; //hey I want to use the namespace release this time
var a:ClassA = new ClassA();
a.test( "hello world" ); // and now you can directly access the method
//will trace "release: hello world"Pretty neat if you ask me. why ? You can really isolate your debug and release logic keeping the same method names, But that's also my point, you do carry the two implementations, so you should be able to switch betweeen them. selectable namespacesA namespace is a constant, you can not change it's value. Let's transform our example, so you can switch from one namespace to another. package test
{
public class ClassA
{
private var _ns:Namespace; //your variable
public function ClassA( ns:Namespace = null )
{
if( !ns )
{
ns = debug;
}
_ns = ns; //you assign a value
}
public function test( msg:String ):void
{
_ns::test( msg ); //you reuse your var
}
debug function test( msg:String ):void
{
trace( "debug: " + msg );
}
release function test( msg:String ):void
{
trace( "release: " + msg );
}
}
}wait, wait, wait ... To really understand that you need more infos about namespaces. package test
{
public namespace debug;
}and package com.whatever
{
public namespace debug;
}same name but different identities!! In the class above, we're passing the namespace as a reference. In the comment above when I say "you reuse your var", you could see that as "you reuse the identity of the namespace". in code you can do that with a property of your class this["test"]( "hello world" ); if test is a public method, or a visible method, the slot will be resolved from the string "test" so when we do that public function test( msg:String ):void
{
_ns::test( msg ); //you reuse your var
}_ns got resolved to the namespace we pass in the constructor, but there we can only pass the reference. We define 3 methods test, one in the public namespace, one in the debug namespace and one in the release namespace. The method in the public namespace is just a redirector who use the namespace notation. Let's use it import test.ClassA;
import test.debug;
var a:ClassA = new ClassA( debug ); //you pass your reference
a.test( "hello world" );
//will trace "debug: hello world"So what happen really ? you save the namespace debug in the _ns variable Let's use it more import test.ClassA;
import test.debug;
import test.release;
var a:ClassA = new ClassA( debug );
a.test( "hello world" );
//will trace "debug: hello world"
var b:ClassA = new ClassA( release );
b.test( "hello world" );
//will trace "release: hello world"And you can do endless variations, for example, you could store the namespace in a public variable of the class and not even pass it to the constructor and so something like import test.ClassA;
import test.debug;
import test.release;
var a:ClassA = new ClassA();
a.context = debug;
a.test( "hello world" );
//will trace "debug: hello world"
a.context = release;
a.test( "hello world" );
//will trace "release: hello world"neat tricks with namespacesOverride the trace functionOh yes you can. Let's see how :). package test
{
public class ClassA
{
public function ClassA()
{
}
public function test( msg:String ):void
{
trace( msg );
}
protected function trace( msg:String ):void
{
public::trace( "[ " + msg + " ]" );
}
}
}The function trace is defined in the public namespace at the anonymous package level, But here in the context of your class, if you define a trace function either in the protected or private namespace, your function will take the priority over the public trace. At the end you still want to use the trace function, so you explicitly use the full path No hack here, you just use your language to the fullest. TODO (more to come)
| |
Can't wait to see the unit test helper!
Hi,
When I use the same example, I am seeing an error message - "a file found in a source-path cannot have more than one externally visible definition". And the location of this error is unknown.
Can you please help me in handling this error?
Thanks
when you receive this error "a file found in a source-path cannot have more than one externally visible definition" that means you try to define more than one public definition per file
you HAVE TO declare the definitions in separate files
eg.
src |_ test |_ debug.as |_ release.as |_ ClassA.asa single .as file can contain the definition of either
when you declare a namespace
package test { public namespace debug; }you can consider "debug" as a constant, eg. it is unique and can not be redefined