-
Notifications
You must be signed in to change notification settings - Fork 10
Namespaces
Namespaces in BCS work similar to namespaces in other languages like C++ and C#. The .
operator is used to access the objects of a namespace:
namespace Test {
int v = 123;
void F() { Print( d: v ); }
enum { C = 321 };
}
script "Main" open {
Test.v = Test.C;
Test.F(); // Output: 321
}
A nested namespace can be declared in one go:
// These are the same:
namespace A { namespace B { namespace C {} } }
namespace A.B.C {}
To avoid confusion with global
variables, the global namespace is called the upmost namespace. The upmost
keyword refers to the upmost namespace:
int a = 123;
namespace Test {
int a = 321;
script "Main" open {
Print( d: a ); // Output: 321
Print( d: upmost.a ); // Output: 123
}
}
In a namespace, the magic identifier, __NAMESPACE__
, is present. __NAMESPACE__
is a string that contains the full name of the namespace where __NAMESPACE__
is used. The upmost namespace does not have an actual name, so when __NAMESPACE__
is used in the upmost namespace, the empty string (""
) is returned.
The following example uses __NAMESPACE__
. Note that the string returned is in lowercase because identifiers in ACS and BCS get lowercased during compilation.
namespace A.B.C {
script 1 open {
Print( s: __NAMESPACE__ ); // Output: a.b.c
}
}
script 2 open {
Print( s: __NAMESPACE__ ); // Output:
}
The strict
qualifier enables strong types. It tells the compiler not to implicitly cast values of a primitive type to raw
:
strict namespace Test {
script "Main" open {
int value1 = "abc"; // Error: initializer of wrong type.
str value2 = "abc"; // All good.
}
}
The strict
qualifier also enables block scoping. For every local declaration, the let
keyword is implied, so you don't need to specify it:
strict namespace Test {
script "Main" open {
int var = 123;
{
int var = 321;
}
}
}
If you don't want to use namespaces but still want strong types and block scoping, you can wrap your code in a nameless namespace block and qualify it with strict
. The nameless namespace block will have the name of the parent namespace block; if there is no parent block, the nameless namespace block will be a part of the upmost namespace:
// This namespace block is part of the upmost namespace.
strict namespace {
// Value and variable must have the same type:
int a = ( int ) "abc";
script "Main" open {
// Block scoping enabled by default. No need for the `let` keyword:
for ( int i = 0; i < 10; ++i ) {}
for ( int i = 0; i < 10; ++i ) {}
}
}
The using
directive is used to import objects from a namespace. You can either import a whole namespace or import specific objects from a namespace.
using namespace ;
You can import a whole namespace. This will make all of the objects in the specified namespace available for use:
namespace Test {
int v = 123;
void F() { Print( d: v ); }
enum { C = 321 };
}
// All of the objects in the `Test` namespace will now be available.
using Test;
script "Main" open {
v = C;
F();
}
using namespace : [enum|struct] [alias =] object [, ...] ;
If you need only a few objects from a namespace, you can import only those objects you want. You can give the imported object a different name if you like:
namespace Test {
int v = 123;
void F() { Print( d: v ); }
enum { C = 321 };
}
// Import only `v` and `C` from the `Test` namespace. `C` is referred to as
// `CONSTANT`.
using Test: v, CONSTANT = C;
script "Main" open {
v = CONSTANT;
Test.F(); // Output: 321
}