Prev |
Scope |
---|
When a binding is made, it rarely affects the entire piece of software. The scope of a binding is that part of a program where the binding is in effect. |
Scope within a single definition | ||
---|---|---|
Most languages use the lexical scope rule, which relies on a definition of a notion of a block. Definitions made in a block are visible only in that block. In C++, a block is a compound statement {...} or a function definition or a for-loop. Figure out the scopes of bindings in the following. void sort(int a[], int n) { int i = 1; while(i < n) { int j = i; while(j > 0 && a[j] < a[j-1]) { int t = a[i]; a[i] = a[j]; a[j] = t; j = j - 1; } i = i + 1; } }
|
Scope at the global level | ||||
---|---|---|---|---|
Some older languages, such as Algol 60, tried to use the local scope rule on the scale of an entire program. You hide a function definition (limiting its scope) by placing it inside another function that needs to use it. integer procedure outer(x); integer x; begin integer procedure inner(integer y) integer y; begin ... end; ... (Use function inner here) end; That does not work well, though. Here is a typical scenario. You are implementing a hash table module. Several functions (insert, lookup, delete) need to share a function locate that finds where a thing should go in a hash table. You want to make locate available to those functions, but not to other functions. But you cannot put it inside insert, or it becomes invisible to lookup and delete. Using the local scope rule, all you can do is make locate visible to all functions. A different approach is based on modules. A module is a collection of things (think of it as a collection of identifier bindings) that can be used to control the scope of bindings.
|
Naming on a large scale | ||
---|---|---|
Software can be built by combining modules from various sources, coming from all over the world. When you are selecting names for things, you need to think on a global scale. What if two different modules, produced in different countries, each define a function called frog, taking an integer parameter and producing an integer. Then you cannot put those two modules into the same piece of software. You cannot use overloading to decide which one you want, since they have the same type, and type information is usually the means of disambiguating overloaded names. A solution is to use very long names. A function defined by the Amphibian division of the Animal.com corporation might call their function com.Animal.Amphibian.frog. Well chosen long names solve the name conflict problem. But they are certainly inconvenient. It is awkward to write x = com.Animal.Amphibian.from(y);To compute a square root in Ada, you write S = Ada.Numerics.GenericElementaryFunctions.Sqrt(X);A solution to this inconvience is a way of shortening names. Typically, you allow writing short names for a collection of long names. In Ada, writing use Ada.Numerics.GenericElementaryFunctions;allows you to write S = Sqrt(X);You do this kind of thing when name conflicts are not a problem, and you avoid it when name conflicts rear their heads.
|
Prev |