diff --git a/tconfpy.3 b/tconfpy.3 index 7d304ee..629a221 100644 --- a/tconfpy.3 +++ b/tconfpy.3 @@ -1078,33 +1078,141 @@ [FOO[BAR]] = Something Or Other .fi -.SS Lexical Namespaces +.SS Introducing 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: +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 - Foo = Bar - Baz = [Foo] + MyCar.Brand = Ferrari + MyCar.Model = 250 GTO + MyCar.Color = Red + + # And so on ... .fi -What this -.B really -means to \*(TC is this: +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 - MYNS.Foo = MYNS.Bar - MYNS.Baz = [MYNS.Foo] + [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