Log inSkip to content

April 13th, 2008

Namespace and URI

Recently I played a little bit with namespaces in ActionScript 3 and found a somewhat weird thing. Namespaces have an associated URI which makes them unique. When you define a namespace you can specify an explicit URI or you can omit it. In the latter case the compiler will assign a unique value automatically, so everything should work perfectly. Class members placed into a namespace can be referenced by two ways:

1) by opening the namespace and then referring to the desired member:

1
2
use namespace something;
myFunction();

2) by qualifying the method or property with the namespace:

1
something::myFunction();

This is what the documentation says. But in practice when I omit the URI only the first way will work and the second one will not. The compiler passes over, everything seems to be OK, but suddenly my namespaces defined without URI are not found at run-time. E.g. I have a package where I define two namespaces, one without an explicit URI and one with a URI:

first.as

1
2
3
package mypackage {
  public namespace first;
}

second.as

1
2
3
package mypackage {
  public namespace second = "http://tengerstudio.com/namespace/second";
}

And also there is a class using them and defining some methods placed into the above two namespaces:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package mypackage {
  public class MyClass {
    first function doSomething(): void {
      trace("doing something");
    }
 
    first function doSomethingElse(): void {
      trace("doing something else 1");
    }
 
    second function doSomethingElse(): void {
      trace("doing something else 2");
    }
  }
}

This all works, yet, so I instantiate this class and try to invoke the doSomething() method:

1
2
3
4
5
6
7
import mypackage.*;
 
var obj: MyClass = new MyClass();
 
use namespace first;
 
obj.doSomething();

This works. But if I use the namespace qualifier, a ReferenceError is thrown:

1
2
3
4
5
import mypackage.*;
 
var obj: MyClass = new MyClass();
 
obj.first::doSomething();

The result is:

ReferenceError: Error #1069: Property mypackage:first::doSomething not found on mypackage.MyClass and there is no default value.
at namespace2_fla::MainTimeline/frame1()

It can be avoided of course if I use the first method, but sometimes it’s not possible, e.g. when there are two or more identical identifiers in different namespaces (as in the case of the doSomethingElse() methods in MyClass) and I want to use all of them.

1
2
3
4
5
6
7
8
9
import mypackage.*;
 
var obj: MyClass = new MyClass();
 
use namespace first;
obj.doSomethingElse();
 
use namespace second;
obj.doSomethingElse();

It will result in a compiler error saying that the reference to doSomething() is ambiguous (of course). But when I try to avoid this and specify exact namespaces:

1
2
3
4
5
6
7
import mypackage.*;
 
var obj: MyClass = new MyClass();
 
obj.first::doSomethingElse();
 
obj.second::doSomethingElse();

I get a run-time error:

ReferenceError: Error #1069: Property mypackage:first::doSomething not found on mypackage.MyClass and there is no default value.
at namespace2_fla::MainTimeline/frame1()

The result is the same when I include the use namespace statement. If I don’t refer to namespace first (which has no associated URI), there is no error, namespace second is working (which has a URI), and if I add a URI to namespace first it will run perfectly, too:

1
2
3
package mypackage {
  public namespace first = "http://tengerstudio.com/namespace/first";
}

What is the conclusion? Never forget to associate a URI with a namespace, even if the documentation says that this is optional.

Well, beside the above ones I mention one more thing related to namespaces, which was not evident to me, but finally I figured out how to use it. This is accessing a namespace defined in a class rather than in a package:

1
2
3
4
5
6
7
8
9
10
11
package mypackage {
 
  public class MyClass2 {
 
    public namespace third = "http://tengerstudio.com/namespace/third";
 
    third function foo(): void {
      trace("foo");
    }
  }
}

The only way I could access and use what is in namespace third was placing it’s value into a variable and referring to the members through this variable:

1
2
3
4
5
6
7
import mypackage.*;
 
var obj: MyClass2 = new MyClass2();
 
var ns: Namespace = MyClass2.third;
 
obj.ns::foo();

So it seems that namespaces defined in a class are always static members, although the static attribute is not allowed on namespace definitions (it throws a compiler error). No other ways worked for me including these ones:

// 1
obj.third::foo();

// 2
obj.(MyClass2.third)::foo();

// 3
use namespace MyClass2.third;
obj.third::foo();

// 4
var ns: Namespace = MyClass.third;
use namespace ns;
obj.foo();

What is also interesting, that I can omit the URI at the definition of namespace third and it will work through the variable reference, so only package level namespaces require URI for using them as direct qualifiers.

2 comments

  1. AS3 Namespaces « GDTech Says:

    [...] AS3 Namespaces http://blog.tengerstudio.com/2008/04/13/namespace-and-uri/ [...]

  2. makc Says:

    This is helpful. I mean it, see this box2d thread for example: http://www.box2d.org/forum/viewtopic.php?f=8&t=1789&start=10 :)

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">



Calendar

April 2008
S M T W T F S
    May »
 12345
6789101112
13141516171819
20212223242526
27282930  

Categories