Started fleshing out the details on lexical namespaces.
1 parent 3d30637 commit 34241d156fbd53e3908de8a20c40f4f9089ad9e7
@tundra tundra authored on 9 Apr 2004
Showing 1 changed file
View
268
tconfpy.3
 
[FOO[BAR]] = Something Or Other
.fi
 
.SS Lexical Namespaces
 
The discussion of variable assignment and reference needs to be
expanded now to include the idea of "lexical namespaces". Think of a
namespace as just being the current context for variables - a way to
group variables together. The idea is that a variable name or
reference is always relative to the current namespace. That is, the
"real" name of the variable is the concatenation of the current
namespace with the variable's name.
 
For instance, suppose the current namespace is "MYNS" and we see the
following in a configuration file:
 
.nf
Foo = Bar
Baz = [Foo]
.fi
 
What this
.B really
means to \*(TC is this:
 
.nf
MYNS.Foo = MYNS.Bar
MYNS.Baz = [MYNS.Foo]
.fi
.SS Introducing Lexical Namespaces
 
So far,the discussion of variables and references has conveniently
ignored the presence of another related \*(TC feature, "lexical
namespaces." Namespaces are a way to automatically group
related variables together. Suppose you wanted to describe
the options on your car in a configuration file. You might do
this:
 
.nf
MyCar.Brand = Ferrari
MyCar.Model = 250 GTO
MyCar.Color = Red
# And so on ...
.fi
 
You'll notice that every variable start with the "thing" that
each item has in common - they are features of \'MyCar\'.
We can simplify this considerably by introducing a lexical namespace:
 
.nf
[MyCar]
 
Brand = Ferrari
Model = 250 GTO
Color = Red
.fi
 
The first statement looks like a variable reference, but it is not.
.B A string inside square brackets by itself on a line introduces a namespace.
The first statement in this example sets the namespace to \'MyCar\'.
From that point forward until the namespace is changed again, every
variable assignment
.B and
reference is "relative" to the namespace. What this really means is
that \*(TC sticks the namspace plus a period in front of every
variable assigned or referenced. It does this automatically and
invisibly, so \'Brand\' is turned into \'MyCar.Brand\' and so on. You
can actually check this by loading the example above into a test
configuration file and running the \'test-tc\' program on it. You will
see the "fully qualified" variable names that actually were loaded
into the symbol table, each beginning with \'MyCar.\' and ending with
the variable name you specified.
 
Realize that this is entirely a naming "trick". \*(TC has no clue
what the namespace
.B means,
it just combines the current namespace with the variable name to
create the actual variable name that will be returned in the symbol
table.
 
You're likely scratching your head wondering why on earth this
feature present in \*(TC. There are, in fact, several reasons for it:
 
.IP \(bu 4
 
It reduces typing repetetive information throughout the configuration
file. In turn, this reduces the likelyhood of a typographical or
spelling error.
 
.IP \(bu 4
 
It helps visibly organize the configuration file. A namespace makes
it clear which variables are related to each other somehow. This is no
big deal in small configurations, but \*(TC was written with the idea
of supporting configuration files that might contain thousands or
even tens of thousands of entries.
 
.IP \(bu 4
 
It simplifies the application programmer's job. Say I want to write a
program that extracts all the information about your car from the
configuration file, but I don't know ahead of time how many things you
will describe. All I really have to know is that you are using
\'MyCar\' as the namespace for this information. My program can then
just scan the symbol table after the configuration file has been parsed,
looking for variables whose name begins with \'MyCar.\'. So if you
want to add other details about your auto like, say, \'Age\', \'Price\',
and so on, you can do so later
.B and the program does not have to be rewritten.
 
.IP \(bu 4
 
It helps enforce correct configuration files. By default, you can
introduce new namespaces into the configuration file any time you
like. However, as described in the previous section on the
\*(TC API, the application programmer can limit you to a pre-defined
set of legal namespaces (via the \'AllowNewNamespaces=False\' API
option). By doing this, the programmer is helping you avoid
incorrect configuration file entries by limiting just which
namespaces you can enter to reference or create variables.
 
 
.SS Lexical Namespace Specifics
 
Creating and using lexical namespaces is fairly straightforward,
but there are a few restrictions and rules:
 
.IP \(bu 4
 
The default initial namespace is the empty string, "". In this one case,
\*(TC does nothing to variables assigned or referenced. That's
why our early examples of how to assign a value to a variable and
then reference those value in the previous section worked.
When the namespace is "", nothing is done to the variable names.
The namespace, "", is also called the "root namespace."
 
Bear in mind that the programmer can change this default namespace to
something other than "" before the configuration file is parsed. If
they do this, they would be well advised to let their users know this
fact.
 
.IP \(bu 4
There two ways to change to a new namespace:
 
.nf
[NewNameSpace] # Must appear on a line by itself or with a comment only
NAMESPACE = NewNamespace
.fi
 
If, at any point, you want to return to the root namespace, you can use
one of these two methods:
 
.nf
[]
NAMESPACE =
.fi
 
So, why are there two ways to do the same thing?
 
 
 
 
 
In other words, \*(TC always prepends the current namespace (plus a
separating period) to any variable assignment or reference it finds in
a configuration. The one exception is when the namespace is "", in