The Working Programmer's Guide To Variables - Scope, Lifetime And More
Written by Mike James   
Thursday, 22 August 2019
Article Index
The Working Programmer's Guide To Variables - Scope, Lifetime And More
Scope
Objects And Lifetimes
Visibility

Objects and Namespaces

However you shouldn't write off the idea of the global variable because it has new life in the form of object oriented programming.

In this paradigm the objects are the fundamental modular division used to divide a program up into manageable chunks. Each object keeps its variables local and even private i.e. inaccessible from outside of the code that makes up the object however in many designs the main objects themselves have what are effectively global names. 

 

Banner

 

This is the reason we have had to introduce the idea of namespaces.

A name is now promoted to something much more involved. Now you can assign a very long and complicated name which you hope will not collide with other similar names.

For example:

mycompany.myproject.myframework.myclass1

might be the name of a class that you would otherwise have just named myclass1.

Obviously there is a lot less chance of collision if you use the long name than if you use the short name - but the long name is a bit of a nuisance to type.

The solution is the introduction of a namespace - basically a default prefix added to all variables. That is if you are working in the namespace:

mycompany.myproject.myframework

then when you use the name myclass1 it is assumed you mean:

mycompany.myproject.myframework.myclass1

Of course if you want to use myclass1 in a different name space then you can do so but only if you enter the complete qualified name of the class you really want to use. For example:

anothercompany.myproject.myclass1

is a different class from the one you created.

To make things easier various looser name space rules are generally used. For example, if you use an unqualified name then each name space is searched until a fully qualified name (FQN) is found. If more than one FQN is found that matches then the collision is brought to the programmer's notice and a fully or partly qualified name has to be used to resolve the ambiguity.

Put simply name spaces were introduced to control global names.

You may have noticed that this entire discussion has been in terms of class rather than object. The same ideas apply, however, to objects, i.e. instances of classes.

Your project has a name space associated with it and when you create a new object it too has a fully qualified name given by appending the name space. Of course it's up to you to keep everything under control and avoid name collisions within your own small naming universe.

Name spaces aren't perfect but they are the only way we have of keeping global names under control.

variablescope

Block scope

After considering the elevated topic of objects and namespaces let's return to the nitty gritty of variables and their scope.

You might think that local or global variables were the only two possibilities but there is another.

If the language that you are using has a block structure, and most modern languages do, then you can use the block structure to determine the scope.

The most extreme form of block structure is where a function can have functions defined within it and they can have functions defined with in them and so on. This is a form of nesting of one function inside another that most object oriented languages have given up - it isn't particularly useful when you have the range of organisational schemes that objects give you. However, even object oriented languages allow you to nest the definition of a class within another class and even allow nested blocks of code within a method or function.

What all this comes down to is that most languages recognise a nested organization of code into blocks of various sorts inside blocks. 

If you do write programs using block structure then an easy to implement and understand scope rule is that a variable is defined in any blocks contained within the block that the variable is declared in.

This produces a sort of halfway between a local and a global variable. The variable is local to all blocks that are defined outside of the block that the variable is declared in but effectively global to all blocks defined within the block that declares the variable.

You can also think of local and global variables as being special cases of the nested scope rule. Global variables are simply variables declared in a block that contains every other block and local variables are declared in a block that contains only the procedure that they are local to.

For example, consider the following short extract:

private void MyMethod(){
 {
  int i = 1;
  {
   i = 2;
  }
 }
}

The use of code blocks within a method is so rare that you might not even recognise this as valid code - it's C# and it is valid.

There are two code blocks defined within the method. The variable i is declared in the first block and its scope is the first block and all blocks that it contains. Thus the assignment in the inner second block is valid and it assigns 2 to the variable i declared in the outer block. Notice that the method doesn't have a variable called i defined in its "top level" scope. That is you try to use a variable called i within the method i.e. outside of the block it is declared in then an error results.

Now consider the following:

{
 int i = 1;
 {
  i = 2;
 }
}
{
 int i = 4;
}

This too is perfectly valid in C#.  The variable i declared in the final block is only in scope within its block and it doesn't interfere or clash with the i defined in the first block.

JavaScript recently introduced block scope via a new keyword - let. If you write

var i;

then the variable has function scope i.e. it is defined in the containing function or global if it is at the top level. However if you write:

let i;

then the variable has block scope and is only defined within the immediately containing block which might just be a function. Block scope variables mean you can define a variable for use in a loop and be sure that it wont clash with an already declared variable outside of the block. 

When you are first learning any block structured language the scope rules seem a bit complicated and so there is a tendency to not make use of them and concentrate on learning the language. After a while you end up all but forgetting them, with only the occasional memory jog from reading the bit in the manual every time a new version of the language appears.

However, from a more sophisticated point of view the way that the scope rule works is very clever and very close to the way that you actually want to work most of the time. It also it a bit like an inheritance mechanism for data, each inner block inheriting all of the outer blocks variables and procedures.



Last Updated ( Thursday, 22 August 2019 )