Presentation is loading. Please wait.

Presentation is loading. Please wait.

ISBN 0-321-33025-0 Chapter 5 Names, Bindings, Type Checking, and Scopes.

Similar presentations


Presentation on theme: "ISBN 0-321-33025-0 Chapter 5 Names, Bindings, Type Checking, and Scopes."— Presentation transcript:

1 ISBN 0-321-33025-0 Chapter 5 Names, Bindings, Type Checking, and Scopes

2 1-2 Type Compatibility

3 1-3 Name Type Compatibility Name type compatibility means that two variables have compatible types only if they are in either the same declaration or in declarations that use the same type name.

4 1-4 Structure Type Compatibility Structure type compatibility means that two variables have compatible types if their types have identical structures.

5 1-5 Name Type Compatibility Is Highly Restrictive Name type compatibility is easy to implement but is highly restrictive. –E.g. Under a strict interpretation, a variable that is a subrange of the integers would not be compatible with an integer type variable.

6 1-6 Determine the Name Type Compatibility of Two Variables Under name type compatibility, only the two type names must be compared to determine compatibility.

7 1-7 Example Supposing Ada used strict name type compatibility, consider the following Ada code: type Indextype is 1..100; count : Ineger; index : Indextype; The variables count and index would not be compatible; count could not be assigned to index or vice versa.

8 1-8 A Problem of Name Type Compatibility When a structured type is passed among subprograms through parameters, such a type must be defined only once, globally. A subprogram cannot state the type of such formal parameters in local terms. –This is the case with the original version of Pascal.

9 1-9 Properties of Structure Type Compatibility Structure type compatibility is more flexible than name type compatibility, but it is more difficult to implement. –Under structure type compatibility, the entire structures of the two types must be compared.

10 1-10 Structure type compatibility disallows differentiating between types with the same structure. –For example, consider the following declarations: type celsius = Float; fahrenheit = Float; –Variables of these two types are considered compatible under structure type compatibility, allowing them to be mixed in expressions. –The above compatibility is undesirable, because in general, types with different names are likely to be abstractions of different categories of problem values and should not be considered equivalent. A Weakness of Structure Type Compatibility

11 1-11 Type Compatibility of Ada Ada GENERALLY uses name type compatibility. Ada provides two type constructs, subtypes and derived types to create types from existing types.

12 1-12 Derived Types An Ada derived type is a NEW type that is based on some previously defined type with which it is incompatible, although it may have identical structure. Derived types inherit all the properties of their parent types. Derived types can also include range constraints on the parent type, while still inheriting all of the parent's operations.

13 1-13 Example of Derived Types type celsius is new FLOAT; type fahrenheit is new FLOAT; –Variables of these two derived types are not compatible, although their structures are identical. –Furthermore, variables of both type are incompatible with any other floating-point type.

14 1-14 The Type of Literals in Ada Literals are exempt from the rule imposed upon derived types. A literal such as 3.0 has the type universal real and is compatible with any floating- point type.

15 1-15 Ada Subtypes An Ada subtype is a possibly range- constrained version of an existing type. A subtype is compatible with its parent type.

16 1-16 Ada Subtype Example For example, consider the following declaration: subtype Small_type is Integer range 0..99; Variables of type Small_type are compatible with Integer variables.

17 1-17 Array Types in Ada Array types may be –constrained types or –unconstrained types.

18 1-18 Constrained Array Types in Ada Constrained array types have a predefined size. E.g. type Int_Buffer is array (1..10) of Integer;

19 1-19 Unconstrained Array Types Unconstrained Array Types in Ada In Ada we can also declare unconstrained array types. That means, when the array is declared, the index type is specified but there is no need to state limits for the index, instead the symbol <> is used. When an object of an unconstrained array type is declared, the index constraints must be stated. type Vector is array (Integer range <>) of Character; Vector_1 : Vector (1.. 10);

20 1-20 Type Compatibility for Ada Unconstrained Array Type For variables of an Ada unconstrained array type, structure compatibility is used. In Ada if two variables –have the same number of elements and –are of the same unconstrained array type, then these two variables are compatible.

21 1-21 Example For example, consider the following type declaration and two object declarations type Vector is array (Integer range <>) of Integer; Vector 1: Vector (1..10); Vector 2: Vector (11..20); These two objects are compatible, even though they have different names and different subscript ranges, because both types have ten elements and the elements of both are of type Integer.

22 1-22 Scope

23 1-23 The Scope of a Program Variable The scope of a program variable is the range of statements in which the variable is visible. A variable is visible in a statement if it can be referenced in that statement.

24 1-24 The Scope Rules of a Language determine how a particular occurrence of a name is associated with a variable. determine how references to variables declared outside the currently executing subprogram or block are associated with their declarations and thus their attributes.

25 1-25 Local Variables vs. Non-local Variables A variable is local in a program unit or block if it is declared there. The nonlocal variables of a program unit or block are those that are visible within the program unit or block but are not declared there.

26 1-26 Static Scoping Static scoping is thus named because the scope of a variable can be statically determined, that is, prior to execution.

27 1-27 Categories of Static-scoped Languages Those in which subprograms can be nested, which creates nested static scopes. –Ada, JavaScript, and PHP allow nested subprograms, which can create a hierarchy of scopes in a program. –but the C-based languages do not. Those in which subprograms cannot be nested.

28 1-28 Assumption The discussion of static scoping in this chapter focuses on those languages that allow nested subgprgrams. So, for now we assume that all scopes are associated with program units.

29 1-29 Determine the Attributes of a Referred Variable For a reference to a variable, the attributes of the variable can be determined by finding the statement in which it is declared.

30 1-30 Find the Declaration Statement of a Variable in Static Scoped Languages with Nested Subprograms Suppose a reference is made to a variable x in subprogram sub1. The correct declaration is found by first searching the declarations of subprogram sub1. –If no declaration is found for the variable there, the search continues in the declarations of the subprogram that declared subprogram sub1, which is called its static parent. If a declaration of x is not found there, the search continues to the next larger enclosing unit (the unit that declared sub1 's parent), and so forth, until –a declaration for x is found or –the largest unit's declarations have been searched without success. In that case, an undeclared variable error has been detected.

31 1-31 Static Ancestors of a Subprogram The static parent of subprogram Sub1, and its static parent, and so forth up to and including the largest enclosing subprogram, are called the static ancestors of Sub1.

32 1-32 A Static Scoping Example procedure Big is X : Integer; procedure Sub1 is begin -- of Sub1...X... end; -- of Sub1 Procedure Sub2 is X : Integer; begin -- of Sub2... end; -- of Sub2 begin -- of Big... end; -- of Big Under static scoping, the reference to the variable X in Subl is to the X declared in the procedure Big. This is true because the search for X begins in the procedure in which the reference occurs, Subl, but no declaration for X is found there. The search thus continues in the static parent of Subl, Big, where the declaration of X is found.

33 1-33 Hide Variable Declarations In some languages that use static scoping, regardless of whether nested subprograms are allowed, some variable declarations can be hidden from some other code segments.

34 1-34 Example void sub() { int count; … while (…) { int count; count++; … } … } The reference to count in the while loop is to that loop’s local count. In this case, the count of sub is hidden from the code inside the while loop. In general, a declaration for a variable effectively hides any declaration of a variable with the same name in a larger enclosing scope.

35 1-35 Selective References In Ada, hidden variables from ancestor scopes can be accessed with selective references, which include the ancestor scope's name. –For example, in the preceding procedure, Big, the X declared in Big can be accessed in Sub1 by the reference Big.X.

36 1-36 Global Variables Although C and C++ do not allow subprograms to be nested inside other subprogram definitions, they do have global variables. These variables are declared outside any subprogram definition. Local variables can hide these globals, as in Ada. In C++, such hidden globals can be accessed using the scope operator ( :: ). –For example, if x is a global that is hidden in a subprogram by a local named x, the global could be referenced as :: x.

37 1-37 Blocks Many languages allow NEW static scopes to be defined in the midst of executable code. This powerful concept, introduced in ALGOL 60, allows a section of code to have its own local variables whose scope is minimized. Such variables are typically stack dynamic, so they have their storage allocated when the section is entered and deallocated when the section is exited. Such a section of code is called a block.

38 1-38 Specify Blocks in Ada In Ada, blocks are specified with declare clauses, as in... declare TEMP : Integer; begin Temp := First; First := Second; Second := Temp; end;...

39 1-39 In C-based Languages Blocks Could Be Created by Compound Statements The C-based languages (such as C, C++, and Java) allow any compound statement (a statement sequence surrounded by matched braces) to have declarations and thus define a new scope. Such compound statements are blocks. For example, if list were an integer array, one could write if (list[i] < listf[j]) { int temp; temp = list[i]; list[i] = listf[j]; llst[j] = temp; }

40 1-40 Scopes Created by Blocks The scopes created by blocks are treated exactly like those created by subprograms. References to variables in a block that are not declared there are connected to declarations by searching enclosing scopes in order of increasing size.

41 1-41 Scope Rules for C++ and C C++ allows variable definitions to appear anywhere in functions. –When a definition appears at a position other than at the beginning of a function, but not within a block, that variable's scope is from its definition statement to the end of the function. Note that in C, all data declarations in a function but not in blocks within the function MUST appear at the beginning of the function.

42 1-42 Scope Rules for Variables Defined in for Statements in C++, Java, and C# The for statements of C++, Java, and C# allow variable definitions in their initialization expressions. In early versions of C++, the scope of such a variable was from its definition to the end of the smallest enclosing block. In the draft standard version, however, the scope is restricted to the for construct, as is the case with Java.

43 1-43 Evaluation of Static Scoping

44 1-44 Assumptions for the Analysis of the Drawbacks of Static Scoping Static scoping provides a method of nonlocal access that works well in many situations. However, it is not without its problems. Based on the program whose skeletal structure is shown in Figure 5.1, in the following slides, we will discuss its weakness. For the program in Figure 5.1, assume that all scopes are created by the definitions of the main program and the procedures.

45 1-45 This program contains an overall scope for main, with two procedures that define scopes inside main, A and B. Inside A are scopes for the procedures C and D. Inside B is the scope of procedure E. We assume that the necessary data and procedure access determined the structure of this program. The required procedure access is as follows: main can call A and B, A can call C and D, and B can call A and E. The Structure of an Example Program

46 1-46 View the structure of the program as a tree in which each node represents a procedure and thus a scope. A tree representation of the program of Figure 5.1 is shown in Figure 5.2. The Tree Representation of the Scopes of the Previous Example Program

47 1-47 However, a graph of the potential procedure calls of this system, shown in Figure 5.3, shows that a great deal of calling opportunity beyond that required is possible. The Potential Call Graph of the Previous Example Program

48 1-48 The Graph of the Desirable Calls

49 1-49 Access to Procedures Should Be Restricted A programmer could mistakenly call a subprogram that should not have been callable, which would not be detected as an error by the compiler. The above situation delays detection of the error until run time, which may make its correction more costly. Therefore, access to procedures should be restricted to those that are necessary.

50 1-50 Unnecessary Visibility of Varialbes Too much data access is a closely related problem. –For example, all variables declared in the main program are visible to all of the procedures, whether or not that is desired, and there is no way to avoid it.

51 1-51 Assumptions Suppose that after the program has been developed and tested, a modification of its specification is required. In particular, suppose that procedure E must now gain access to some variables of the scope of D.

52 1-52 Solution One (Moving E inside the Scope of D ) and Its Drawback One way to provide that access is to move E inside the scope of D. But then E can no longer access the scope of B, which it presumably needs (otherwise, why was it there?).

53 1-53 Solution Two (Moving Variables Needed into main Procedure) and Its Weakness Another solution is to move the variables defined in D that are needed by E into main. This would allow access by all the procedures, which would be more than is needed and thus creates the possibility of incorrect accesses. –For example, a misspelled identifier in a procedure can be taken as a reference to an identifier in some enclosing scope, instead of being detected as an error.

54 1-54 Another Disadvantage of Solution Two – Variables Needed Becomes Invisible Suppose the variable that is moved to main is named x, and x is needed by D and E. But suppose that there is a variable named x declared in A. That would hide the correct x from its original owner, D.

55 1-55 More Disadvantage of Solution Two One final problem with moving the declaration of x to main is that it is harmful to readability to have the declaration of variables so far from their uses.

56 1-56 Problems of Subprogram Visibility with Static Scoping [Premise] In the tree of Figure 5.2, suppose that, due to some specification change, procedure E needed to call procedure D. –The above change could only be accomplished by moving D to nest directly in main, assuming that it was also needed by either A or C. –It would then also lose access to the variables defined in A. –This solution, when used repeatedly, results in programs that begin with long lists of low-level utility procedures.

57 1-57 Drawbacks of Static Scoping Designers are encouraged to use far more globals than are necessary. All procedures can end up being nested at the same level, in the main program, using globals instead of deeper levels of nesting.

58 1-58 Dynamic Scoping Dynamic scoping is based on the calling sequence of subprograms, not on their spatial relationship to each other. Thus the scope can be determined only at run time.

59 1-59 Example Program Dynamic scoping rules apply to nonlocal references. The meaning of the identifier X referenced in Sub1 is dynamic—it cannot be determined at compile time. It may reference the variable from either declaration of X, depending on the calling sequence. procedure Big is X : Integer; procedure Sub1 is begin -- of Sub1...X... end; -- of Sub1 Procedure Sub2 is X : Integer; begin -- of Sub2... end; -- of Sub2 begin -- of Big... end; -- of Big

60 1-60 Finding the Meaning of a X of the Previous Program One way the correct meaning of X can be determined at run time is to begin the search with the local declarations. –This is also the way static scoping began, but that is where the similarity between the two techniques ends. When the search of local declarations fails, the declarations of the dynamic parent, or calling procedure, are searched. –If a declaration for X is not found there, the search continues in that procedure's dynamic parent, and so forth, until a declaration for X is found. If none is found in any dynamic ancestor, it is a run-time error.

61 1-61 Examples of Finding the Declaration of a Variable Consider the two different call sequences for Sub1 in the example above. –First, Big calls Sub2, which calls Sub1. In this case, the search proceeds from the local procedure, Sub1, to its caller, Sub2, where a declaration for X is found. So the reference to X in Sub1 in this case is to the X declared in Sub2. –Next, Sub1 is called directly from Big. In this case, the dynamic parent of Sub1 is Big, and the reference is to the X declared in Big. P.S.: If static scoping were used, in either calling sequence discussed, the reference to X in Sub1 would be to Big ’s X.

62 1-62 Properties of Dynamic Scoping The correct attributes of nonlocal variables visible to a program statement cannot be determined statically. Furthermore, such variables are not always the same. –A statement in a subprogram that contains a reference to a nonlocal variable can refer to different nonlocal variables during different executions of the subprogam.

63 1-63 Programming Problems Caused by Dynamic Scoping – (1) During the time span beginning when a subprogram begins its execution and ending when that execution ends, the local variables of the subprogram are all visible to any other executing subprogram, regardless of its textual proximity. There is no way to protect local variables from this accessibility. Subprograms are always executed in the immediate environment of the caller; therefore, dynamic scoping results in less reliable programs than static scoping.

64 1-64 Programming Problems Caused by Dynamic Scoping – (2) A second problem with dynamic scoping is the inability to statically type check references to nonlocals. This results from the inability to statically determine the declaration for a variable referenced as a nonlocal.

65 1-65 Programming Problems Caused by Dynamic Scoping – (3) Dynamic scoping also makes programs much more difficult to read, because the calling sequence of subprograms must be known to determine the meaning of references to nonlocal variables.

66 1-66 Programming Problems Caused by Dynamic Scoping – (4) Finally, accesses to nonlocal variables in dynamic scoped languages take far longer than accesses to nonlocals when static scoping is used. The reason for this is explained in Chapter 10.

67 1-67 Advantage of Dynamic Scoping In some cases, the parameters passed from one subprogram to another are simply variables that are defined in the caller. NONE of these need to be passed in a dynamically scoped language, because they are implicitly visible in the called subprogram.

68 1-68 Dynamic Scoping Is not as Widely Used as Static Scoping Programs in static scoped languages –are easier to read –are more reliable –execute faster than equivalent programs in dynamic scoped languages. It was precisely for these reasons that dynamic scoping was replaced by static scoping in most current dialects of LISP.

69 1-69 Scope vs. Lifetime Scope and lifetime are different concepts. Static scope is a textual, or spatial, concept whereas lifetime is a temporal concept.

70 1-70 The Scope and Lifetime of a C and C++ Variable – (1) In C and C++, a variable that is declared in a function using the specifier static is statically bound to the scope of that function and is also statically bound to storage. So its scope is static and local to the function, but its lifetime extends over the entire execution of the program of which it is a part.

71 1-71 Consider the following C++ functions: void printheader() {... } /* end of printheader */ void compute() { int sum;... printheader(); } /* end of compute */ The scope of the variable sum is completely contained within the compute function. It does not extend to the body of the function printheader, although printheader executes in the midst of the execution of compute. However, the lifetime of sum extends over the time during which printheader executes. Whatever storage location sum is bound to before the call to printheader, that binding will continue during and after the execution of printheader. The Scope and Lifetime of a C and C++ Variable – (2)

72 1-72 Referencing Environments

73 1-73 Referencing Environment The referencing environment of a statement is the collection of all variables that are visible in the statement.

74 1-74 The Referencing Environment of a Statement in a Static-scoped Language The referencing environment of a statement in a static-scoped language is the variables declared in its local scope plus the collection of all variables of its ancestor scopes that are visible. In such a language, the referencing environment of a statement is needed while that statement is being compiled, so code and data structures can be created to allow references to variables from other scopes during run time.

75 1-75 The Referencing Environment of a Statement in Ada In Ada, scopes can be created by procedure definitions. The referencing environment of a statement includes the local variables, plus all of the variables declared in the procedures in which the statement is nested (excluding variables in nonlocal scopes that are hidden by declarations in nearer procedures). Each procedure definition creates a new scope and thus a new environment.

76 1-76 procedure Example is A, B : Integer;... procedure Sub1 is X, Y : Integer; begin -- of Subl... 1 end; -- of Subl procedure Sub2 is X : Integer;... procedure Sub3 is X : Integer; begin -- of Sub3... 2 end; -- of Sub3 begin -- of Sub2... 3 end; -- of Sub2 begin –- of Example... 4 end. –- of Example The referencing environments of the indicated program points are as follows; Point Referencing Environment 1 X and Y of Sub1, A and B of Example 2 X of Sub3, ( X of Sub2 is hidden), A and B of Example 3 X of Sub2, A and B of Example The Referencing Environment of an Ada Example Program

77 1-77 Analysis of the Previous Example Although the scope of Sub1 is at a higher level (it is less deeply nested) than Sub3, the scope of Sub1 is not a static ancestor of Sub3, so Sub3 does not have access to the variables declared in Sub1. –P.S.: The variables declared in Sub1 are stack dynamic, so they are not bound to storage if Sub1 is not in execution. Because Sub3 can be in execution when Sub1 is not, it cannot be allowed to access variables in Sub1, which would not necessarily be bound to storage during the execution of Sub3.

78 1-78 Active Subprograms A subprogram is active if its execution has begun but has not yet terminated.

79 1-79 The Referencing Environment of a Statement in a Dynamically Scoped Language The referencing environment of a statement in a dynamically scoped language is the locally declared variables, plus the variables of all other subprograms that are currently active. Once again, some variables in active subprograms can be hidden from the referencing environment. –Recent subprogram activations can have declarations for variables that hide variables with the same names in previous subprogram activations.

80 1-80 Referencing Environment Examples Consider the following example program. Assume that the only function calls are the following: main calls sub2, which calls sub1. void subl() { int a, b;... 1 } /* end of subl */ void sub2 { int b, c;... 2 subl; } /* end of sub2 */ void main() { int c, d;... 3 sub2(); } /* end of main */ The referencing environments of the indicated program points are as follows: Point Referencing Environment 1 a and b of sub1, c of sub2, d of main,, ( c of main and b of sub2 are hidden) 2 b and c of sub2, d of main, ( c of main is hidden) 3 c and d of main

81 1-81 Named Constants A named constant is a variable that is bound to a value only at the time it is bound to storage; its value CANNOT be changed by assignment or by an input statement.

82 1-82 Advantages of Named Constants Named constants are useful as aids to readability and program reliability. Readability can be improved. –For example, by using the name pi instead of the constant 3.14159.

83 1-83 Another Advantages of Named Constants In a program that process a fixed number of data values, say 100. Such a program usually use the constant 100 in a number of locations –for declaring array subscript ranges –for loop control limits –and other uses. When this program must be modified to deal with a different number of data values, all occurrences of 100 must be found and changed. On a large program, this can be tedious and error- prone. An easier and more reliable method is to use a named constant.

84 1-84 Example – Named Constants Are Not Used void example() { int[] intList = new int[100]; String[] strList = new String[100];... for (index = 0; index < 100; index++) {... } for (index = 0; index < 100; index++) {... } average = sum / 100;... }

85 1-85 Example – Named Constants Are Used void example() { final int len = 100; int[] intList = new int[len]; String[] strList = new String[len];... for (index = 0; index < len; index++) {... } for (index = 0; index < len; index++) {... } average = sum / len;... }

86 1-86 Further Analysis of the Previous Program Now when the length must be changed, only one line must be changed (the parameter len ), regardless of the number of times it is used in the program. This is another example of the benefits of abstraction. The name len is an abstraction for the number of elements in some arrays and the number of iterations in some loops. This illustrates how named constants can aid modifiability.

87 1-87 Manifest Constants Fortran 95 allows only constant expressions to be used as the values of its named constants. These constant expressions can contain –previously declared named constants –constant values –operators The reason for the restriction to constants and constant expressions in Fortran 95 is that it uses static binding of values to named constants. Named constants in languages that use static binding of values are sometimes called manifest constants.

88 1-88 Initialization In many instances, it is convenient for variables to have values before the code of the program or subprogram in which they are declared begins executing. The binding of a variable to a value at the time it is bound to storage is called initialization. –If the variable is statically bound to storage, binding and initialization occur before run time. In these cases, the initial value must be specified as a literal or an expression whose only nonliteral operands are named constants that have already been defined. –If the storage binding is dynamic, initialization is also dynamic and the initial values can be any expression.

89 1-89 Example In most languages, initialization is specified on the declaration that creates the variable. –For example, in C++, we could have int sum = 0; int* ptrSum = ∑ char name[] = “George Washintton Carver”;

90 1-90 Summary Case sensitivity and the relationship of names to special words represent design issues of names Variables are characterized by the sextuples: name, address, value, type, lifetime, scope Binding is the association of attributes with program entities Scalar variables are categorized as: static, stack dynamic, explicit heap dynamic, implicit heap dynamic Strong typing means detecting all type errors


Download ppt "ISBN 0-321-33025-0 Chapter 5 Names, Bindings, Type Checking, and Scopes."

Similar presentations


Ads by Google