Scope of Identifier

In computer programming, scope is an enclosing context where values and expressions are associated. Various programming languages have various types of scopes. Typically, scope is used to define the extent of information hiding – that is, the visibility or accessibility of variables from different parts of the program. Scopes can:
  • contain declarations or definitions of identifiers;
  • contain statements and/or expressions which define an executable algorithm or part thereof;
  • nest or be nested.
Scope is a property of the program text and is made independent of the runtime call stack by the language implementation. Because this matching only requires analysis of the static program text, this type of scoping is also called static scoping. Lexical scoping is standard in all ALGOL-based languages such as Pascal, Modula2 and Ada as well as in modern functional languages such as ML and Haskell. It is also used in the C language and its syntactic and semantic relatives, although with different kinds of limitations. Static scoping allows the programmer to reason about object references such as parameters, variables, constants, types, functions, etc. as simple name substitutions. This makes it much easier to make modular code and reason about it, since the local naming structure can be understood in isolation. In contrast, dynamic scope forces the programmer to anticipate all possible dynamic contexts in which the module’s code may be invoked.
It is important to have a good understanding of scope because if you try to use an Identifier that’s not in scope, you will get the compiler error. An Identifier is available only after its definition has ended, meaning that is not usually possible to define an Identifier in terms of itself. The portion of the program where an identifier can be used is known as its scope. For example, when we declare a local variable in a block, it can be referenced only in that block and in blocks nested within that block. The type of scope is always determined by the location of which you declare the Identifier (except for labels which always have function scope) There are four type of scopes: function, file, block and function prototype.

1. Block Scope

Objective-C code is divided into sequences of code blocks and files that define the structure of a program. Each block, referred to as a statement block, is encapsulated by braces ({}). Each block has its own scope. No conflict occurs if the same identifier is declared in two blocks. If one block encloses the other, the declaration in the enclosed block hides that in the enclosing block until the end of the enclosed block is reached. We may also state that when the block is exited, the names declared in the block are no longer available.
When one block is nested inside another, the variables from the outer block are usually visible in the nested block. However, if the declaration of a variable in a nested block has the same name as a variable that is declared in an enclosing block, the declaration in the nested block hides the variable that was declared in the enclosing block. The original declaration is restored when program control returns to the outer block. This is called block visibility. For example:
#include <stdio.h>
int main(){
    int i = 32;            /* block scope 1*/
    printf("Within the outer block: i=%d\n", i);
    {
        int i, j;         /* block scope 2, int i hides the outer int i*/
        printf("Within the inner block:\n");
        for (i=0, j=10; i<=10; i++, j--){
            printf("i=%2d, j=%2d\n", i, j);
        }
    }                     /* the end of the inner block */
    printf("Within the outer block: i=%d\n", i);
    return 0;
}
Program Output:
Within the outer block: i=32
Within the inner block:
i= 0, j=10
i= 1, j= 9
i= 2, j= 8
i= 3, j= 7
i= 4, j= 6
i= 5, j= 5
i= 6, j= 4
i= 7, j= 3
i= 8, j= 2
i= 9, j= 1
i=10, j= 0
Within the outer block: i=32

2. Function scope

A label is the only kind of identifier that has function scope. A label is declared implicitly by its use in a statement. Label names must be unique within a function.

3. File scope

Identifiers appearing outside of any block, function, or function prototype, have file scope. Identifier names with file scope are often called “global” or “external.” The scope of a global identifier begins at the point of its definition or declaration and terminates at the end of the translation unit. Unlike other scopes, multiple declarations of the same identifier with file scope can exist in a compilation unit, so long as the declarations are compatible.
Some coding guidelines documents recommend that the number of objects declared at file scope be minimized. However, there have been no studies showing that alternative design/coding techniques would have a more worthwhile cost/benefit associated with their use. Identifiers declared as types must appear at file scope if:
  • objects declared to have these types appear at file scope,
  • objects declared to have these types appear within more than one function definition (having multiple, textual, declarations of the same type in different block scopes is likely to increase the cost of maintenance and C does not support the passing of types as parameters),
  • other types, at files scope, reference these types in their own declaration.
Any program using file scope objects can be written in a form that does not use file scope objects. This can be achieved either by putting all statements in the function main, or by passing, what were file scope, objects as parameters. The following are some of the advantages of defining objects at file scope (rather than passing the values they contain via parameters) include:
  • Efficiency of execution. Accessing objects at file scope does not incur any parameter passing overheads. The execution-time efficiency and storage issues are likely to be a consideration in a freestanding environment, and unlikely to be an issue in a hosted environment.
  • Minimizes the cost of adding new function definitions to existing source code. If the information needed by the new function is not available in a visible object, it will have to be passed as an argument.
The function calling the new function now has a requirement to access this information, to pass it as a parameter. This requirement goes back through all call chains that go through the newly created function. If the objects that need to be accessed have file scope, there will be no need to add any new arguments to function calls and parameters to existing function definitions.
The following are some of the disadvantages of defining objects at file scope:
  • Storage is used for the duration of program execution.
  • There is a single instance of object. Most functions are not recursive, so separate objects for nested invocations of a function are not usually necessary.
  • Reorganizing a program by moving function definitions into different translation units requires considering the objects they access. These may need to be given external linkage.
  • Greater visibility of identifiers reduces the developer effort needed to access them, leading to a greater number of temporary accesses.
  • Information flow between functions is implicit. Developers need to make a greater investment in comprehending which calls cause which objects to be modified. Experience shows that developers tend to overestimate the reliability of their knowledge of which functions access which file scope identifiers.
  • When reading the source of a translation unit, it is usually necessary to remember all of the file scope objects defined within it. Reducing the number of file scope objects reduces the amount of information that needs to be in developers long-term memory.
The only checks made on references to file scope objects is that they are visible and that the necessary type requirements are met. For issues, such as information flow, objects required to have certain values at certain points are not checked (such checking is in the realm of formal checking against specifications). Passing information via parameters does not guarantee that mistakes will not be made; but the need to provide arguments acts as a reminder of the information accessed by a function and the possible consequences of the call.

4. Function prototype

The declarator or type specifier for an identifier with function-prototype scope appears within the list of parameter declarations in a function prototype (not part of the function declaration). Its scope terminates at the end of the function declarator.For example:
int students ( int david, int susan, int mary, int john );
In this example, the identifiers (david, susan, mary , and john ) have scope beginning at their declarations and ending at the closing parenthesis. The type of the function students is “function returning int with four int parameters.” In effect, these identifiers are merely placeholders for the actual parameter names to be used after the function is defined.

INTERNATIONAL STANDARD – Programming languages –  C, described the Scopes of an Identifiers as under:

1. An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter. The same identifier can denote different entities at different points in the program. A member of an enumeration is called an enumeration constant. Macro names and macro parameters are not considered further here, because prior to the semantic phase of program translation any occurrences of macro names in the source file are replaced by the preprocessing token sequences that constitute their macro definitions.
2. For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope. Different entities designated by the same identifier either have different scopes, or are in different name spaces. There are four kinds of scopes: function, file, block, and function prototype. (A function prototype is a declaration of a function that declares the types of its parameters.)
3. A label name is the only kind of identifier that has function scope. It can be used (in a goto statement) anywhere in the function in which it appears, and is declared implicitly by its syntactic appearance (followed by a : and a statement).
4. Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit. If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block. If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator. If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
5. Unless explicitly stated otherwise, where this International Standard uses the term ‘‘identifier’’ to refer to some entity (as opposed to the syntactic construct), it refers to the entity in the relevant name space whose declaration is visible at the point the identifier occurs.
6. Two identifiers have the same scope if and only if their scopes terminate at the same point.
7. Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag. Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list. Any other identifier has scope that begins just after the completion of its declarator.
8. As a special case, a type name (which is not a declaration of an identifier) is considered to have a scope that begins just after the place within the type name where the omitted identifier would appear where it not omitted.
Advertisements
Tagged , , , , ,
%d bloggers like this: