Previous:#declare vs. #local   Main Index   Next:Destroying Identifiers with #undef



Identifier Name Collisions

Local identifiers may have the same names as previously declared identifiers. In this instance, the most recent, most local identifier takes precedence. Upon entering an include file or invoking a macro, a new symbol table is created. When referencing identifiers, the most recently created symbol table is searched first, then the next most recent and so on back to the global table of the main scene file. As each macro or include file is exited, its table and identifiers are destroyed. Parameters passed by value reside in the same symbol table as the one used for identifiers local to the macro.

The rules for duplicate identifiers may seem complicated when multiply-nested includes and macros are involved, but in actual practice the results are generally what you intended.

Consider this example: You have a main scene file called myscene.pov and it contains

 #declare A = 123;

 #declare B = rgb<1,2,3>;

 #declare C = 0;

 #include "myinc.inc"

Inside the include file you invoke a macro called MyMacro(J,K,L). Note it isn't important where MyMacro is defined as long as it is defined before it is invoked. In this example, it is important that the macro is invoked from within myinc.inc.

The identifiers A, B, and C are generally available at all levels. If either myinc.inc or MyMacro contain a line such as #declare C=C+1; then the value C is changed everywhere as you might expect.

Now suppose inside myinc.inc you do...

 #local A = 546;

The main version of A is hidden and a new A is created. This new A is also available inside MyMacro because MyMacro is nested inside myinc.inc. Once you exit myinc.inc, the local A is destroyed and the original A with its value of 123 is now in effect. Once you have created the local A inside myinc.inc, there is no way to reference the original global A unless you #undef A or exit the include file. Using #undef always undefines the most local version of an identifier.

Similarly if MyMacro contained...

 #local B = box{0,1}

then a new identifier B is created local to the macro only. The original value of B remains hidden but is restored when the macro is finished. Note that the local B need not have the same type as the original.

The complication comes when trying to assign a new value to an identifier at one level that was declared local at an earlier level. Suppose inside myinc.inc you do...

 #local D = 789;

If you are inside myinc.inc and you want to increment D by one, you might try to do...

 #local D = D + 1;

but if you try to do that inside MyMacro you'll create a new D which is local to MyMacro and not the D which is external to MyMacro but local to myinc.inc. Therefore you've said "create a MyMacro D from the value of myinc.inc's D plus one". That's probably not what you wanted. Instead you should do...

 #declare D = D + 1;

You might think this creates a new D that is global but it actually increments the myinc.inc version of D. Confusing isn't it? Here are the rules:

1.) When referencing an identifier, you always get the most recent, most local version. By "referencing" we mean using the value of the identifier in a POV-Ray statement or using it on the right of an equals sign in either a #declare or #local.

2.) When declaring an identifier using the #local keyword, the identifier which is created or has a new value assigned, is ALWAYS created at the current nesting level of macros or include files.

3.) When declaring a NEW, NON-EXISTANT identifier using #declare, it is created as fully global. It is put in the symbol table of the main scene file.

4.) When ASSIGNING A VALUE TO AN EXISTING identifier using #declare, it assigns it to the most recent, most local version at the time.

In summary, #local always means "the current level", and #declare means "global" for new identifiers and "most recent" for existing identifiers.



Previous:#declare vs. #local   Main Index   Next:Destroying Identifiers with #undef