Presentation is loading. Please wait.

Presentation is loading. Please wait.

Names and Binding Imperative programming has instructions that manipulate the “state” of the process the “state” is the collection of variables and their.

Similar presentations


Presentation on theme: "Names and Binding Imperative programming has instructions that manipulate the “state” of the process the “state” is the collection of variables and their."— Presentation transcript:

1 Names and Binding Imperative programming has instructions that manipulate the “state” of the process the “state” is the collection of variables and their values For variables: storage, binding, types, scope Design issues for identifiers maximum length for the name? what are the legal characters? COBOL uses – for connectors which detracts from readability are letters case sensitive? if so, this can detract from both readability and writability are the special words of the language context sensitive (key words) or reserved? in FORTRAN, INTEGER and REAL are context sensitive leading to this possibility INTEGER REAL REAL INTEGER The idea behind a keyword, as seen in FORTRAN, tends to be confusing and harm readability and writability, and therefore most languages have moved away from the keyword to the reserved word in which case you are just not allowed to use the given word in any context other than as it is expected.

2 Variables A variable is an abstraction of
a memory location (for reference) type-specific methods to perform operations The address is sometimes referred to as the l-value Aliases arise when multiple identifiers refer to the same memory location, created through pointers pointing at the same allocated piece of memory parameter passing using pass by reference union types (covered in chapter 6) Type specifies allowable range of values and allowable operations Value current value stored in memory, referred to as the r-value

3 Binding Binding is the association of an object to its attributes, operations, or name there are many different types of bindings bindings can occur at different times design time binding: binding * to multiplication language implementation time binding: int size and operations compile time binding: binding type to a variable (as in int x; ) link time binding: binding function name to a specific function definition load time binding: binding variable to memory location run time binding: binding variable to memory location or bind a polymorphic variable to specific class type Binding is static if it occurs before run time and remains unchanged, otherwise binding is dynamic

4 Bindings: Variable Declarations
Binding the identifier name to the declared type Are variables declared explicitly or implicitly? most languages historically have required explicit variable declarations exceptions are FORTRAN (based on first letter of variable name, I..N for integer, otherwise real) BASIC and PL/I (type binding occurs when variable is first assigned a value) some recent languages use type inference (ML, Haskell, Miranda, F#), type is determined by compiler based on given operations Scripting/interpreted languages often have dynamic binding where variables are typeless see the next slide Static type binding permits compile time type checking, making the language safer. It also creates restrictions on how a variable can be used, which means that the language is less flexible, This is often a reasonable tradeoff however as most programmers do not mind declaring variables. In earlier programming days when memory was limited, typeless variables meant that a programmer could use fewer variables, which ultimately saved memory. But dynamic type binding is slower than static type binding as well as being less safe. Consider this code: x = 5 y = 3.1 x = y * x Is this safe? Now consider x = “hello”

5 Dynamic Type Binding Introduced in LISP
binding of type is not explicit derived by examining assignment statements at runtime variable can store different types at different types this is commonly handled by using a pointer so that the compiler only has to worry about creating storage for an address and then the type is bound based on when the value is allocated memory at run-time Other languages that use dynamic type binding include JavaScript, Perl, JavaScript, Ruby, and PHP note that in Perl, different types of variables are determined by their name $name is a is an array, %name is a hash structure In JavaScript and Lisp you have to declare local variables but not type them

6 Static Lifetime The lifetime is the time from which a variable is bound to memory until it is unbound a static lifetime means that the variable is bound before program execution begins and remains the same until program termination Variables are statically bound if they are global variables variables in a C function declared as static variables in a FORTRAN subroutine this allows the subprogram to retain the value of the variable after the subprogram terminates but prohibits recursion or shadowing Static is the most efficient form of binding access is performed using direct memory addressing mode no overhead needed for allocation or deallocation at runtime Shadowing means that you can have more than 1 variable of the same name. In Ada for instance, you can declare a variable to be of the same name and still obtain the older variable by using notation like this: funct1.x for the version of x declared in funct1, as opposed to x which was declared in the current scope. With static variables, there is only one version of the variable. Thus, recursion is not allowed because recursion will allow for one version of the variable for each active recursive call (for both local variables and parameters). Consider this C function: int fact(int x) { if (x <= 1) return 1; else return x * fact(x-1); } When called with fact (3), we have x = 3, which calls fact(2) where we have x = 2, which calls fact(1) where we have x = 1. If we had a single storage location for x, we could not accommodate the 2 recursive calls, or at least their associated parameter x.

7 Stack Dynamic Lifetime
Variable bound when execution reaches variable’s declaration in the code – through run-time stack local variables, parameters for Algol-descended languages (C/C++/Java, Pascal, Ada, etc) also, variables declared within a block Allocation and deallocation are performed by the run-time environment allows for recursion requires extra run-time overhead Variable unbound (popped off the stack) when the code that contains the local var/parameter terminates and thus is no longer available/accessible FORTRAN 95 includes a Save list instruction to save the list of variables somewhere other than the stack if you want to retain a variable’s value in C, declare it as static We will cover the run-time stack in detail in chapter 10 where we will see how stack dynamic variables are managed.

8 Explicit Dynamic Lifetime
Variable storage allocated/deallocated explicitly at runtime from the heap heap memory is nameless and accessed by pointers pointer itself may be named (e.g., int *p; ) or pointed to by another pointer if itself was allocated on the heap Allocation instructions differ by language C/C++: malloc, calloc, free, C++ also uses new for objects Pascal, Ada: new, free Java, C#: new, no deallocation instruction PL/I: allocate, free C# has parameters that can be either stack dynamic or explicit dynamic The variable’s type is bound at compile time even though the variable’s memory is not allocated until run-time note that since memory deallocation is often OS specific some languages do not actually implement a deallocation routine

9 Implicit Dynamic Lifetime
Variable’s memory bound while it is assigned a value variable’s attributes bound during this time if the variable is unbound and bound to a new memory location, then its attributes (including type) can change Lisp and JavaScript both use this approach ALGOL 58 has “flex” for arrays also used this approach memory comes from the heap but no explicit allocation or deallocation (deallocation handled by garbage collection) this form of lifetime has the highest degree of flexibility but also highest amount of overhead no compile-time type checking is possible since type can change any type checking (if performed at all), must be done at run-time allows for Generic code which can operate on any type

10 Type Checking Ensures that operands of an operator are compatible
compatible type is either one that is legal for the operator or is allowed via an implicit coercion (automatic conversion from one type to another) for instance, an int can be coerced into a float and a float into a double but not the other way A type error (often called a type mismatch) occurs if an operand is not appropriate for an operator and cannot be coerced If all bindings of variable to type are static, then type checking can be done completely at compile time dynamically typed languages like Lisp, JavaScript and APL perform dynamic (run-time) type checking only type checking is complicated if a memory location can store different types at different times of a program’s execution (known as a Union type)

11 Strongly Typed A language is strongly typed if all type checking errors are detectable before run-time a more restrictive definition is if every identifier in a program has a single type associated with it and known at compile time Both definitions require static binding of variables Being strongly typed is desirable because it offers the best reliability with regard to type errors the problem with having a strongly typed language is that it removes flexibility To be strongly typed, a language cannot have dynamic type binding union types implicit coercions and unchecked conversions

12 A Look at Various Languages
Few languages are strongly typed because nearly all languages have a mechanism to get around type checking FORTRAN – in early versions, parameters were not checked, union types Pascal – variant records are a type of union C, C++ – optional parameters are not typed, union types available, pointers can be void pointers (another union type) Ada, Java and C# – close to strongly typed in that no type errors can arise implicitly, however, all three languages have unchecked conversions which can lead to typing errors APL, SNOBOL, LISP – dynamic type binding ML, F# - strongly typed through type inference Consider in C that a pointer can be declared as void *. This means that the pointer could point to any number of types. Therefore, a compiler is not able to confirm that a given instruction will be permitted at run-time when it is compiling the program. In Java and C#, pointers are explicitly typed, but using a cast on primitive types is allowed and therefore, we can still have a run-time error in some occasions. Another situation arises as follows: float a, b; double c, d; d = a + c; This seems straightforward – a is coerced into a double before the addition is performed. But if the programmer meant to type a + b, then the resulting addition should be coerced into a double only after the addition is performed. This could potentially result in the wrong value being stored in d. In a strongly typed language, an error will have arisen at compile time to prevent the potentially incorrect answer.

13 Type Compatibility Type compatibility determines whether a type error should arise or not types are compatible if one is coercible into another Languages determine compatibility based two strategies name type compatibility variables declared using the same declaration or the same type example: int x; int y; // x and y are name type compatible compatible by structure variables have the same structure even though they are of differently named types, for example: struct foo { int x; float y; }; struct bar { int x; float y;}; foo a; bar b; // a and b are structure type compatible C uses compatibility by structure, C++ uses name compatibility Ada uses name compatibility except for anonymous arrays which use structure compatibility

14 Scope Scope is the range of statements from which a variable is “visible” where the variable can be referenced Scope rules determine how the name being referenced is associated with a particular memory location this is necessary when dealing with non-local references to variables, or when variables are re-declared inside of blocks Two forms of scope: static and dynamic nearly all languages use static scope because it is easier to understand and type checking can be performed at compile time LISP is one of the few that has used dynamic scope (although it now uses static scope unless overridden) the Bash interpreter also uses dynamic scope

15 Static Scope Introduced in ALGOL 60 to bind names to non-local variables, copied by most languages since scope for any variable can be determined prior to execution two subtypes of static scoping: subprogram nesting is allowed (Pascal-like languages) and not allowed (C-like languages) if subprograms can be nested, then this creates a hierarchy of scopes formed by the definitions of the subprograms example: sub1 is defined inside of sub2 which is inside of sub3, then a variable referenced in sub3 but not declared in sub3 would be found in sub2, and if not in sub2, then in sub1 if two or more subprograms use the same name for a variable, the reference is to the definition that occurs in the subprogram innermost to the current, whereas the outer variable is “hidden” in Ada, hidden variables can be accessed via notation like: sub1.x

16 Example of Static Scope
Consider a program with nested subprograms: Main contains A and B A contains C and D B contains E In the language of this program, a nested subprogram can call any nested subprogram above it within the same subprogram, and can be called by the subprogram it is nested in so A can call C and D, D can call C, but C cannot call D B (which appears below A) can call A or D but D and C cannot call B or E Example of Static Scope Assume x is declared in MAIN, B and C and assume MAIN calls B calls E calls A calls D calls C If x is referenced in E, it is B’s x whereas if x is referenced in D, it is MAIN’s x (not C’s) because D is statically scoped inside of MAIN but not in C MAIN A B C D E Here is an example of a skeleton of a Pascal program that matches the example in the slide above. With such a structure, Main can call any of the procedures, A can call C or D, D can call C (since C appears above D), B can call E or A (notice that A cannot call B since B appears below A), and all procedures can recursively call themselves. Program Example procedure Main procedure A( ) procedure C( ) begin…end; // C procedure D( ) begin…end; // D begin…end; // A procedure B( ) procedure E( ) begin…end; // E begin…end; // B begin…end. // main

17 Blocks In C-like languages But C-like languages do allow nested blocks
static scoping is not as much an issue because subprograms are not nested inside one another But C-like languages do allow nested blocks blocks have the same scope rules as static scoping a variable is found in the section of code it is referenced, or else you must follow the blocks outward until you reach the definition or reach the end of the function Java and C# do not allow duplication of variables in nested inner blocks so that this is not an issue note that OOPLs have another form of scope, the instance datum whose scope is based on its visibility modifier we will explore this later in the semester

18 Example void scopeexample(int x) {… // reference 1
{ int x; // declaration A … // reference 2 { … // reference 3 { int x; // declaration B … // reference 4 … // reference 5 } … // reference 6 In this example, reference 1 is to the parameter, reference 2 and 3 are to declaration A, reference 4 and 5 are to declaration B, reference 6 is to the parameter again. If x were not the name of the parameter, reference 1, 2 and 6 would yield syntax errors

19 Dynamic Scoping Scope is based on the sequence of calling subprograms
To determine reference search backward through the chain of subprogram calls until the variable declaration is found in a previously active subprogram dynamic scoping harms readability because, at compile-time, you do not know the sequence of subprogram invocations consider three subprograms which all use a variable x and any of which could call the subprogram foo foo accesses x, which x is being accessed? there is no way to know except at run-time this also harms reliability since it makes any program harder to understand Dynamic scoping was used in APL, SNOBOL4, early LISPs

20 Example From the static scope example, if MAIN calls B calls E
- declaration of x SUB1 - declaration of x - ... call SUB2 SUB2 - reference to x - MAIN calls SUB1 SUB1 calls SUB2 SUB2 references x Static scoping – reference to x is to MAIN's x Dynamic scoping - reference to x is to SUB1's x Example From the static scope example, if MAIN calls B calls E calls A calls D, and we access x in D, then we will reference B’s x, not MAIN’s

21 Referencing Environment
This is the collection of variables which are accessible (visible) to a given instruction in the program in statically scoped languages, each statement’s referencing environment can be determined at compile time in dynamically scoped languages, the referencing environment of a statement consists of all variables (local and parameters) in the local subprogram all variables (local and parameters) declared in active subprograms whose names are note the same as those of more recent declarations all global variables if none of the variables/parameters share the same name, then the referencing environment for a dynamically scoped language is all variables/parameters of all active subprograms!

22 Example Referencing Environment at 1: X, Y of Sub1 A, B of Example
procedure Example is A, B : Integer; procedure Sub1 is X, Y : Integer; begin …  1 end; procedure Sub2 is X : Integer; procedure Sub3 is …  2 …  3 …  4 end. Example Referencing Environment at 1: X, Y of Sub1 A, B of Example 2: X of Sub3 A and B of Example (X of Sub2 is hidden but accessible as Sub2.X) 3: X of Sub2, 4: A and B of Example Ada code

23 Constants, Variable Initializations
An identifier bound to a value at the time it is bound to storage and unalterable during its lifetime constants aid readability and reliability of a program Ada, C++, Java allow dynamic binding of constants so that the value is not set by the programmer but can be determined at runtime (for instance, passed into a method as a parameter) For convenience, variable initialization can occur prior to execution FORTRAN: Integer Sum Data Sum /0/ Ada: Sum : Integer :=0; ALGOL 68: int first := 10; C, C++, C#, Java: int num = 5; LISP (Let (x (y 10)) ... )


Download ppt "Names and Binding Imperative programming has instructions that manipulate the “state” of the process the “state” is the collection of variables and their."

Similar presentations


Ads by Google