4 Bindings and Scope  Bindings and environments.

advertisement
4
Bindings and Scope
 Bindings and environments.
 Scope, block structure, and visibility.
 Declarations.
 Blocks.
© 2004, D.A. Watt, University of Glasgow
4-1
Bindings and environments
 PL expressions and commands contain identifiers, which
are declared elsewhere. Their meanings depend on these
declarations.
 A binding is a fixed association between an identifier and
an entity such as a value, variable, or procedure.
 Each declaration produces one or more bindings.
 An environment (or name space) is a set of bindings.
 Each expression or command is interpreted in a particular
environment. Each identifier used in the expression or
command must have a binding in that environment.
4-2
Example: Ada environments
 Ada program outline:
procedure p is
z: constant Integer := 0;
c: Character;
procedure q (x: in Float) is
c: constant Float := 3.0e6;
Environments:
b: Boolean;
{ b  a Boolean variable,
begin
c  the floating-point number 3.0106,
p  a procedure with no parameter,
…
q  a procedure with a Float parameter,
end q;
begin
…
end p;
x  a Float variable,
z  the integer 0 }
{ c  a Character variable,
p  a procedure with no parameter,
q  a procedure with a Float parameter,
4-3
z  the integer 0 }
Scope
 The scope of a declaration (or of a binding) is the portion
of the program text over which it has effect.
 In some early PLs (such as Cobol), the scope of each
declaration was the whole program.
 In modern PLs, the scope of each declaration is controlled
by the program’s block structure.
4-4
Block structure
 A block is a program construct that delimits the scope of
any declarations within it.
 Each PL has its own forms of blocks:
• C: block commands ({ … }), function bodies, compilation units.
• Java: block commands, method bodies, class declarations,
packages.
• Ada: block commands (declare … begin … end;),
procedure bodies, packages, tasks, etc.
 A PL’s block structure is the way in which blocks are
arranged in the program text.
4-5
Example: Ada block structure
 Ada program outline:
procedure P is
…
begin
…
declare
…
begin
…
end;
…
end P;
procedure Q is
…
begin
…
end Q;
4-6
Monolithic block structure
 Some PLs (such as Cobol) have monolithic block
structure: the whole program is a single block. The scope
of every declaration is the whole program.
declaration of x
declaration of y
declaration of z
scope of
declarations
of x, y, z
4-7
Flat block structure
 Some PLs (such as Fortran) have flat block structure: the
program is partitioned into non-overlapping blocks.
declaration of x
declaration
declaration
declarationofof
ofyyy
scope of declaration of x
scope of declaration of y
declaration
declaration
declarationofof
ofzzz
scope of declaration of z
4-8
Nested block structure
 Modern PLs have nested block structure: blocks may be
nested within other blocks.
declaration of x
scope of declaration of x
declaration
declaration of
of yy
scope of declaration of y
declaration
declaration of
of zz
scope of declaration of z
4-9
Scope and visibility
 A binding occurrence of identifier I is an occurrence of I
where I is bound to some entity X.
 An applied occurrence of identifier I is an occurrence of I
where use is made of the entity X to which I is bound.
 At this applied occurrence, we say that I denotes X.
 If the PL is statically scoped (see later), every applied
occurrence of I should correspond to exactly one binding
occurrence of I.
4-10
Example: Ada binding and applied
occurrences
 Ada program outline:
procedure p is
z : constant Integer := 0;
c : Character;
procedure q (x : in Float) is
c : constant Float := 3.0e6;
b : Boolean;
begin
… b … c … x … z …
end q;
begin
… c … z …
end p;
4-11
Hiding
 If identifier I is declared in two different blocks, I denotes
a different entity in each block.
 If identifier I is declared in two nested blocks, I denotes
one entity in the outer block and a different entity in the
inner block. The inner declaration hides the outer one.
declaration of x
declaration of x
declaration of x
declaration of x
Here the outer
declaration of
x is hidden.
4-12
Static vs dynamic scoping (1)
 A PL is statically scoped if the body of a procedure is
executed in the environment of the procedure definition.
• We can decide at compile-time which binding occurrence of an
identifier corresponds to a given applied occurrence.
 A PL is dynamically scoped if the body of a procedure is
executed in the environment of the procedure call.
• We cannot decide until run-time which binding occurrence of an
identifier corresponds to a given applied occurrence, since the
environment may vary from one procedure call to another.
4-13
Example: static vs dynamic scoping (1)
 Program in Ada (which is statically scoped):
s : constant Integer := 2;
function f (x : Integer) return Integer is
begin
The value of s
return s * x;
here is always 2.
end f;
procedure q (y : Integer) is
begin
put(f(y));
end q;
procedure q (z : Integer) is
s : constant Integer := 3;
begin
put(f(z));
end q;
4-14
Example: static vs dynamic scoping (2)
 Same program in a hypothetical dynamically scoped PL:
s : constant Integer := 2;
function f (x : Integer) return Integer is
begin
The value of s
return s * x;
here depends on
end f;
the call site.
procedure q (y : Integer) is
begin
put(f(y));
multiplies value
end q;
of y by 2
procedure q (z : Integer) is
s : constant Integer := 3;
begin
put(f(z));
end q;
multiplies value
of z by 3
4-15
Static vs dynamic scoping (2)
 Dynamic scoping fits badly with static typing.
• In the previous slide, what if the two declarations of s had
different types?
 Nearly all PLs (including C, Java, and Ada) are statically
scoped.
 Only a few PLs (such as Smalltalk and Lisp) are
dynamically scoped.
4-16
Declarations (1)
 A declaration is a program construct that will be
elaborated to produce binding(s).
 A declaration may have side effects (such as creating a
variable).
 A definition is a declaration whose only effect is to
produce binding(s).
4-17
Declarations (2)
 Forms of declarations:
• type declarations
• constant declarations
• variable declarations
• procedure definitions
The repertoire of
simple declarations
depends on the PL.
• …
• collateral declarations
• sequential declarations
• recursive declarations.
4-18
Type declarations
 A type declaration binds an identifier to a type.
 A type definition binds an identifier to an existing type.
 Alternatively, a type declaration may introduce a new type,
distinct from all existing types.
4-19
Example: C type declarations
 “typedef …” binds an identifier to an existing type:
typedef char* Alpha;
Alpha s;
s = t;
char* t;
bound to existing type char*
legal
 But “enum …”, “struct …”, or “union …” binds an
identifier to a new type:
struct Book {Alpha title, int edition};
struct Author {Alpha name, int age};
bound to
Book b; Author a;
new types
a = b;
illegal
4-20
Example: Ada type declarations
 Every Ada type declaration introduces a new and distinct
type:
type Alpha is array (1 .. 32) of Character;
type Book is record
title: Alpha;
edition: Integer;
end record;
type Author is record
name: Alpha;
age: Integer;
end record;
b: Book;
a := b;
bound to
new types
a: Author;
illegal
4-21
Constant declarations
 A constant declaration binds an identifier to a (constant)
value.
 In Ada, a constant declaration has the form:
I : constant T := E;
This binds I to the value of the expression E, which must
be of type T.
 Some PLs restrict the expression E to be a literal, or an
expression that can be evaluated at compile-time.
 Some PLs restrict the constant’s type T.
4-22
Variable declarations
 A variable declaration binds an identifier to a variable.
 In Ada, ordinary variable declarations have the form:
I : T := E;
This creates a variable of type T, binds I to that variable,
and initialises it to the value of the expression E.
 In Ada, renaming variable declarations have the form:
I : T renames V;
This binds I to the existing variable V.
4-23
Example: Ada renaming variable declaration
 Ada code:
type Country is (UK, FR, …);
pop : array (Country) of Natural;
declare
c : Country := …;
p : Integer renames pop(c);
begin
bound to existing variable
…
pop(c)
p := p + 1;
…
more efficient than
end;
pop(c) := pop(c) + 1;
4-24
Procedure definitions
 A procedure definition binds an identifier to a procedure.
 In most PLs, we can define both proper procedures and
function procedures.
4-25
Example: Ada procedure definitions
 Function procedure definition:
function even (n: Integer) return Boolean is
begin
bound to a function procedreturn (n mod 2 = 0);
ure that tests whether its
end;
Integer argument is even
 Proper procedure definition:
procedure double (n: in out Integer) is
begin
bound to a proper procedn := n * 2;
ure that doubles its Integer
end;
argument
4-26
Collateral declarations
 A collateral declaration is a group of subdeclarations that
are elaborated independently of one another.
• A subdeclaration may not use bindings produced by any other
subdeclaration.
 Collateral declarations are found in Java and functional
PLs, but not in C or Ada.
4-27
Sequential declarations
 A sequential declaration is a group of subdeclarations
that are elaborated one after another.
• A subdeclaration may use bindings produced by previous
subdeclarations, but not those produced by following
subdeclarations.
 Sequential declarations are found in all imperative and OO
PLs.
4-28
Recursive declarations
 A recursive declaration is one that uses the bindings it
produces itself.
 Ada type declarations:
• A single type declaration may be recursive.
• A sequence of type declarations may be made mutually recursive,
if preceded by “incomplete type declarations”.
 Ada procedure declarations: similarly.
 Java method definitions:
• One or more method definitions may be (mutually) recursive.
4-29
Example: Ada recursive type declarations
 Mutually recursive type declarations:
type IntNode;
type IntList is access IntNode;
type IntNode is record
head: Integer;
tail: IntList;
end record;
incomplete type
declaration: binds
IntNode to an
unknown type
completes the
binding of
IntNode
4-30
Example: Ada recursive procedure
definitions (1)
 Recursive procedure definition:
procedure print (n: Natural) is
begin
if n < 10 then
put(digit(n));
else
print(n/10);
put(digit(n mod 10));
end if;
end;
4-31
Example: Ada recursive procedure
definitions (2)
 Mutually recursive procedure definitions:
procedure parse_expression;
procedure parse_primary is
begin
if acceptable('(') loop
accept('(');
parse_expression;
accept(')');
else
parse_variable;
end if;
end;
binds parse_
expression to an
unknown procedure
4-32
Example: Ada recursive procedure
definitions (3)
 Mutually recursive procedure definitions (continued):
procedure parse_expression is
begin
parse_primary;
while acceptable('+') loop
accept('+');
parse_primary;
end loop;
end;
completes the
binding of parse_
expression
4-33
Blocks
 A block is a program construct that delimits the scope of
any declarations within it.
 Kinds of blocks:
• block commands
• block expressions.
4-34
Block commands
 A block command is a form of command that contains a
local declaration (or group of declarations) D and a
subcommand C.
 The bindings produced by D are used only for executing C.
These bindings override any bindings for the same
identifiers in the environment outside the block.
 Block commands are common in imperative and OO PLs.
 In C and Java:
{ D C }
 In Ada:
declare D begin C end;
4-35
Example: Java block command
 To sort the values of int variables x and y into ascending
order:
if (x > y)
{ int z = x;
x = y;
y = z;
}
block command
(scope of
declaration of z)
4-36
Block expressions
 A block expression is a form of expression that contains a
local declaration (or group of declarations) D and a
subexpression E.
 The bindings produced by D are used only for evaluating
E. These bindings override any bindings for the same
identifiers in the environment outside the block.
 Block expressions are uncommon in imperative and OO
PLs, but common in functional PLs.
 Form of block expression in Haskell:
let D in E
4-37
Example: Haskell block expression
 To compute the area of a triangle whose sides have lengths
a, b, c:
let
s = (a + b + c)/2.0
in
sqrt(s*(s-a)*(s-b)*(s-c))
 The only way to achieve the same effect in Ada (or C) is to
declare and call a suitable function:
function area (a, b, c: Float)
return Float is
s: constant Float := (a + b + c)/2.0;
begin
return sqrt(s*(s-a)*(s-b)*(s-c));
end;
4-38
Download