4.40 Namespaces


4.40 Namespaces

One really nice feature of records and unions is that the field names are local to a given record or union declaration. That is, you can reuse field names in different records or unions. This is an important feature of HLA because it helps avoid namespace pollution. Namespace pollution occurs when you use up all the "good" names within the current scope and you have to start creating nondescriptive names for some object because you've already used the most appropriate name for something else. Because you can reuse names in different record/union definitions (and you can even reuse those names outside of the record/union definitions) you don't have to dream up new names for the objects that have less meaning. We use the term "namespace" to describe how HLA associates names with a particular object. The field names of a record have a namespace that is limited to objects of that record type. HLA provides a generalization of this namespace mechanism that lets you create arbitrary namespaces. These namespace objects let you shield the names of constants, types, variables, and other objects so their names do not interfere with other declarations in your program.

An HLA namespace section encapsulates a set of generic declarations in much the same way that a record encapsulates a set of variable declarations. A namespace declaration takes the following form:

 namespace name;      << declarations >> end name; 

The name identifier provides the name for the namespace. The identifier after the end clause must exactly match the identifier after namespace. Note that a namespace declaration section is a section unto itself. It does not have to appear in a type or var section. A namespace may appear anywhere one of the HLA declaration sections is legal. A program may contain any number of namespace declarations; in fact, the namespace identifiers don't even have to be unique, as you will soon see.

The declarations that appear between the namespace and end clauses are all the standard HLA declaration sections, except that you cannot nest namespace declarations. You may, however, put const, val, type, static, readonly, storage, and var sections within a namespace.[32] The following code provides an example of a typical namespace declaration in an HLA program:

 namespace myNames;      type           integer: int32;      static           i:integer;           j:uns32;      const           pi:real64 := 3.14159; end myNames; 

To access the fields of a namespace you use the same dot notation that records and unions use. For example, to access the fields of myNames outside of the name space you'd use the following identifiers:

 myNames.integer     - A type declaration equivalent to int32. myNames.i           - An integer variable (int32). myNames.j           - An uns32 variable. myNames.pi           - A real64 constant. 

This example also demonstrates an important point about namespace declarations: within a namespace you may reference other identifiers in that same namespace declaration without using the dot notation. For example, the i field uses type integer from the myNames namespace without the "myNames." prefix.

What is not obvious from the example is that namespace declarations create a clean symbol table whenever you open up a namespace. The only external symbols that HLA recognizes in a namespace declaration are the predefined type identifiers (e.g., int32, uns32, and char). HLA does not recognize any symbols you've declared outside the namespace while it is processing your namespace declaration. This creates a problem if you want to use symbols from outside the namespace when declaring other symbols inside the namespace. For example, suppose the type integer had been defined outside myNames as follows:

 type      integer: int32; namespace myNames;      static           i:integer;           j:uns32;      const           pi:real64 := 3.14159; end myNames; 

If you were to attempt to compile this code, HLA would complain that the symbol integer is undefined. Clearly integer is defined in this program, but HLA hides all external symbols when creating a namespace so that you can reuse (and redefine) those symbols within the namespace. Of course, this doesn't help much if you actually want to use a name that you've defined outside myNames within that namespace. HLA provides a solution to this problem: the @global: operator. If, within a namespace declaration section, you prefix a name with "@global:", then HLA will use the global definition of that name rather than the local definition (if a local definition even exists). To correct the problem in the previous example, you'd use the following code:

 type      integer: int32; namespace myNames;      static           i:@global:integer;           j:uns32;      const           pi:real64 := 3.14159; end myNames; 

With the @global: prefix, the i variable will be type int32 even if a different declaration of integer appears within the myNames namespace.

You cannot nest namespace declarations. Logically, there doesn't seem to be any need for this; hence its omission from the HLA language.

You can have multiple namespace declarations in the same program that use the same name space identifier, e.g.,

 namespace ns;      << declaration group #1 >> end ns;      .      .      . namespace ns;      << declaration group #2 >> end ns; 

When HLA encounters a second namespace declaration for a given identifier, it simply appends the declarations in the second group to the end of the symbol list it created for the first group. Therefore, after processing the two namespace declarations, the ns namespace would contain the set of all symbols you've declared in both namespace blocks.

Perhaps the most common use of namespaces is in library modules. If you create a set of library routines to use in various projects or distribute to others, you have to be careful about the names you choose for your functions and other objects. If you use common names like get and put, the users of your module will complain when your names collide with theirs. An easy solution is to put all your code in a namespace block. Then the only name you have to worry about is the namespace identifier itself. This is the only name that will collide with other users' identifiers. This can happen, but it's much less likely to happen than if you don't use a namespace and your library module introduces dozens, if not hundreds, of new names into the global namespace.[33] The HLA Standard Library provides many good examples of namespaces in use. The HLA Standard Library defines several namespaces like stdout, stdin, str, cs, and chars. You refer to functions in these namespaces using names like stdout.put, stdin.get, cs.intersection, str.eq, and chars.toUpper. The use of namespaces in the HLA Standard Library prevents conflicts with similar names in your own programs.

[32]Procedure and macro declarations, the subjects of later chapters, are also legal within a name space declaration section.

[33]The global namespace is the global section of your program.




The Art of Assembly Language
The Art of Assembly Language
ISBN: 1593272073
EAN: 2147483647
Year: 2005
Pages: 246
Authors: Randall Hyde

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net