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 ID: 699790
Download Presentation The PPT/PDF document "Names and Binding Imperative programming..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
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 INTEGERSlide2
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-valueSlide3
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
dynamicSlide4
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 slideSlide5
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 scalar, @name is an array, %name is a hash structure
In JavaScript
and Lisp you have to declare local variables but not type themSlide6
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 Slide7
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 staticSlide8
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
routineSlide9
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 typeSlide10
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)Slide11
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 conversionsSlide12
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 inferenceSlide13
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 compatibilitySlide14
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 scopeSlide15
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.xSlide16
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
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
MAIN
A
B
C
D
E
A
C
B
E
DSlide17
Blocks
In C-like languages
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 semesterSlide18
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 errorsSlide19
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 LISPsSlide20
Example
MAIN
-
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
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’sSlide21
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!Slide22
Example
procedure Example is
A, B : Integer;
…
procedure Sub1 is
X, Y : Integer;
begin
…
1
end;
procedure Sub2 is
X : Integer;
…
procedure Sub3 is
X : Integer;
begin
… 2
end;
begin
… 3
end;
begin
… 4
end.
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,
A and B of Example
4: A and B of Example
Ada codeSlide23
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)) ... )