PROGRAMMING
LANGUAGES
Module 3
NAME, SCOPE AND
BINDING
A name is a mnemonic character string representing
something else
Name: Identifiers that allow us to refer to variables,
constants, functions, types, operations, and so on
x, sin, f, prog1, null? are names
• Most names are identifiers
Names enable programmers to refer
to variables, constants, operations, and types using
identifier names rather than low-level hardware components
A binding is an association between two things, such as a
name and the thing it names
• e.g. Name of an object and the object
Many properties of a programming language are defined
during its creation.
For instance:
• the meaning of key words such as while or for in C,
• the size of the integer data type in Java, are properties
defined at language design time.
Binding:
• A BINDING is an association, such as between an attribute
and an entity or between an operation and a symbol
• Name and memory location (for variables)
• Name and function
• Typically a binding is between a name and the object it
refers to.
The scope of a binding
is the part of the program
or time interval(s) in the
program’s execution during
which the binding is active.
Binding Time is the point at which a binding is
created or, more generally, the point at which any
implementation decision is made.
The time at which a binding takes place is called binding
time
• language design time
the design of specific program constructs
(syntax), primitive types, and meaning
(semantics)
• - language implementation time
• fixation of implementation constants such as
numeric precision
• max identifier name length
• run-time memory sizes
- program writing time
the programmer's choice of algorithms and data
structures
- compile time
• the time of translation of high-level constructs to
machine code and choice of memory layout for
object
-link time
• the time at which multiple object codes (machine
code files) and libraries are combined into one
executable
- load time
• the time at which the operating system loads the
executable in memory
• choice of physical addresses
-run time
• the time during which a program executes (runs)
Binding Time Sample:
Language feature Binding time
Syntax, e.g. if (a>0) b:=a; in C or
Language design
if a>0 then b:=a end if in Ada
Keywords, e.g. class in C++ and Java Language design
Reserved words, e.g. main in C and
Language design
writeln in Pascal
Meaning of operators, e.g. + (add) Language design
Primitive types, e.g. float
Language design
and struct in C
Internal representation of literals,
Language implementation
e.g. 3.1 and "foo bar"
The specific type of a variable in a
Compile time
C or Pascal declaration
Binding Time Sample:
Language design,
Storage allocation method for a variable language implementation,
and/or compile time
Linking calls to static library routines,
Linker
e.g. printf in C
Merging multiple object codes
Linker
into one executable
Loading executable in memory
Loader (OS)
and adjusting absolute addresses
Nonstatic allocation of space for variable Run time
The terms STATIC and DYNAMIC are generally used to refer
to things bound before run time and at run time,
respectively
• “static” is a coarse term; so is "dynamic“
IT IS DIFFICULT TO OVERSTATE THE IMPORTANCE OF
BINDING TIMES IN PROGRAMMING LANGUAGES
BINDING OF ATTRIBUTES TO VARIABLES
•A binding is static if it occurs before run time and
remains unchanged throughout program execution.
• If it occurs during run time or can change in the course
of program execution, it is called dynamic.
In general, early binding times are associated with greater
efficiency
Later binding times are associated with greater flexibility
Compiled languages tend to have early binding times
Interpreted languages tend to have later binding times
Today, it talk about the binding of identifiers to the variables
they name
Importance of Binding Time:
Early binding
• Faster code
• Typical in compiled languages
Late binding
• Greater flexibility
• Typical in interpreted languages
Scope Rules - control bindings
• Fundamental to all programming languages is the ability
to name data, i.e., to refer to data using symbolic
identifiers rather than addresses
• Not all data is named! For example, dynamic storage in
C or Pascal is referenced by pointers, not names
* •An object has to be stored in memory during its lifetime
•Static objects have an absolute storage address that is retained
throughout the execution of the program
• Global variables
• Subroutine code
• Class method code
•Heap objects may be allocated and deallocated at arbitrary times, but
require an expensive storage management algorithm
•Stack objects are allocated in last-in first-out order, usually in
combination with subroutine calls and returns
•Local variables of a subroutine
•e.g. Java class instances are always stored on the heap
* Heap – is a large area of memory from which the programmer can
allocate blocks as needed, and deallocate them (or allow them to be
garbage collected) when no longer needed.
Object - any entity in the program. Variables, functions..
•Object lifetime - (or life cycle) of an object is the period between the
object creation and destruction.
•Binding lifetime - the period between the creation and destruction
of the binding.
•Usually the binding lifetime is a subset of the object lifetime.
• In many object-oriented languages (OOLs), particularly those
that use garbage collection (GC) – objects are allocated on
the heap.
• the value of a variable holding an object actually corresponds
to a reference to the object, not the object itself, and
destruction of the variable just destroys the reference, not the
underlying object.
Object Destruction
*
• It is generally the case that after an object is used, it is removed
from memory to make room for other programs or objects to take
that object's place.
• However, if there is sufficient memory or a program has a short run
time, object destruction may not occur, memory simply being
deallocated at process termination.
• In some cases object destruction simply consists of deallocating
the memory, particularly in garbage-collected languages, or if the
"object" is actually a plain old data structure.
The period of time from creation to
destruction is called the
LIFETIME of a binding
• If object outlives binding it's garbage
• If binding outlives object it's a dangling reference
Key events
• creation of objects
• creation of bindings
• references to variables (which use bindings)
• (temporary) deactivation of bindings
• reactivation of bindings
• destruction of bindings
• destruction of objects
Storage Allocation mechanisms
• Static
• Stack
• Heap
Static allocation for
• code
• globals
• static or own variables
• explicit constants (including strings, sets, etc)
*
Central stack for
• parameters
• local variables
Why a stack?
• allocate space for recursive routines
(not necessary in FORTRAN – no recursion)
• reuse space
(in all programming languages)
Central stack for
• parameters
• local variables
Why a stack?
• allocate space for recursive routines
(not necessary in FORTRAN – no recursion)
• reuse space
(in all programming languages)
Stack
•very fast access
•don't have to explicitly de-allocate variables
•space is managed efficiently by CPU, memory will not become
fragmented
•local variables only
•limit on stack size (OS-dependent)
•variables cannot be resized
Heap
•variables can be accessed globally
•no limit on memory size
•(relatively) slower access
•no guaranteed efficient use of space, memory may become
fragmented over time as blocks of memory are allocated,
then freed
•you must manage memory (you're in charge of allocating and
freeing variables)
•variables can be resized using realloc()
Local Variables: Stack Allocation
• When we have a declaration of the form “int a;”:
– a variable with identifier “a” and some memory allocated to it
is created in the stack. The attributes of “a” are:
• Name: a
• Data type: int
• Scope: visible only inside the function it is defined,
disappears once we exit the function
• Address: address of the memory location reserved for it.
Note: Memory is allocated in the stack for a even before it
is initialized.
Local Variables: Stack Allocation
• Size: typically 4 bytes
• Value: Will be set once the variable is initialized
•Since the memory allocated for the variable is set in the
beginning itself, we cannot use the stack in cases where
the amount of memory required is not known in advance.
This motivates the need for HEAP
Maintenance of stack
is responsibility of calling sequence
and subroutine prolog and epilog
• space is saved by putting as much in the prolog and epilog
as possible
The epilogue and prologue of a function are simply the set of instructions
that 'set up' the context for the function when it's called and clean up when it
returns.
The prologue typically performs such tasks as:
•saves any registers that the function might use (that are required by the
platform's standard to be preserved across function calls)
•allocates storage on the stack that the function might require for local
variables
•sets up any pointer (or other linkage) to parameters that might be passed
on the stack
The epilogue generally only needs to restore any save registers
and restore the stack pointer such that any memory reserved by
the function for its own use is 'freed'.
The exact mechanisms that might be used in a prologue/epilogue
are dependent on the CPU architecture, the platforms standard,
the arguments and return values of the function, and the
particular calling convention the function might be using.
Heap for dynamic allocation
A scope is a maximal region of the program where no
bindings are destroyed
(e.g., body of a procedure).
In most languages with subroutines, we OPEN a new scope
on subroutine entry:
• create bindings for new local variables,
• make references to variables
A scope in any programming is a region
of the program where a defined variable can
have its existence and beyond that variable
can not be accessed.
Scope of an identifier is the part of the program where the
identifier may directly be accessible. In C, all identifiers
are lexically (or statically) scoped. C scope rules can be covered
under following two categories.
Global Scope: Can be accessed anywhere in a program.
// filename: file1.c
int a;
int main(void)
{
a = 2;
}
int main()
{
{
int x = 10, y = 20;
{ Block Scope: A variable
// The outer block contains declaration of x and y, so
declared in a block is
// following statement is valid and prints 10 and 20
printf("x = %d, y = %d\n", x, y); accessible in the block and all
{ inner blocks of that block, but
// y is declared again, so outer block y is not accessible not accessible outside the
// in this block
int y = 40; block
x++; // Changes the outer block variable x to 11
y++; // Changes this block's variable y to 41
printf("x = %d, y = %d\n", x, y);
}
// This statement accesses only outer block's variables
printf("x = %d, y = %d\n", x, y);
}
}
return 0;
}
Algol 68:
• Algol 68 introduced the term elaboration for the process of
creating bindings when entering a scope. Elaboration time is
a useful concept.
Ada (re-popularized the term elaboration):
• storage may be allocated, tasks started, even exceptions
propagated as a result of the elaboration of declarations
With STATIC (LEXICAL) SCOPE RULES, a scope is defined in terms of
the physical (lexical) structure of the program
• The determination of scopes can be made by the compiler
• Lexical scoping (sometimes known as static scoping ) is a convention
used with many programming languages that sets the scope (range of
functionality) of a variable so that it may only be called (referenced) from
within the block of code in which it is defined.
• The scope is determined when the code is compiled.
Figure:
Programming languages implement
• Static Scoping: active bindings are determined using the text of the
program. The determination of scopes can be made by the compiler.
• Most recent scan of the program from top to bottom
• Most compiled languages employ static scope rules
• Dynamic Scoping: active bindings are determined by the flow of
execution at run time (i.e., the call sequence).
• The determination of scopes can NOT be made by the compiler.
• Dynamic scope rules are usually encountered in interpreted
languages; in particular, early LISP dialects assumed dynamic
scope rules.
The key idea in static scope rules is that bindings are
defined by the physical (lexical) structure of the program.
With dynamic scope rules, bindings depend on the current
state of program execution
• cannot always be resolved by examining the program because
they are dependent on calling sequences
• To resolve a reference, it use the recent, active binding made at
run time
Dynamic scope rules are usually encountered in
interpreted languages
• early LISP dialects assumed dynamic scope rules.
Such languages do not normally have type checking at
compile time because type determination isn't always
possible when dynamic scope rules are in effect
EXAMPLE: STATIC VS. DYNAMIC
program scopes (input, output );
var a : integer;
procedure first;
begin a := 1; end;
procedure second;
var a : integer;
begin first; end;
begin
a := 2; second; write(a);
end.
EXAMPLE: STATIC VS. DYNAMIC
If static scope rules are in effect (as would be the case in
Pascal), the program prints a 1
If dynamic scope rules are in effect, the program prints a 2
Why the difference? At issue is whether the assignment to
the variable a in procedure first changes the variable a
declared in the main program or the variable a declared in
procedure second
EXAMPLE: STATIC VS. DYNAMIC
Static scope rules require that the reference resolve to the most
recent, compile-time binding, namely the global variable a
Dynamic scope rules, on the other hand, require that we choose the
most recent, active binding at run time
• Perhaps the most common use of dynamic scope rules is to provide
implicit parameters to subroutines
• This is generally considered bad programming practice nowadays
• Alternative mechanisms exist
• static variables that can be modified by auxiliary routines
• default and optional parameters
EXAMPLE: STATIC VS. DYNAMIC
At run time it create a binding for a when it enter the main
program.
Then, create another binding for a when it enter procedure
second
• This is the most recent, active binding when procedure first is
executed
• Thus, we modify the variable local to procedure second, not the
global variable
• However, we write the global variable because the variable a local
to procedure second is no longer active
Accessing variables with dynamic scope:
• (1) keep a stack (association list) of all active variables
• When you need to find a variable, hunt down from top
of stack
• This is equivalent to searching the activation records
on the dynamic chain
Accessing variables with dynamic scope:
• (2) keep a central table with one slot for every variable name
• If names cannot be created at run time, the table layout
(and the location of every slot) can be fixed at compile
time
• Otherwise, you'll need a hash function or something to do
lookup
• Every subroutine changes the table entries for its locals at
entry and exit.
(1) gives a slow access but fast calls
(2) gives aslow calls but fast access
In effect, variable lookup in a dynamically-scoped
language corresponds to symbol table lookup in a
statically-scoped language
Because static scope rules tend to be more complicated,
however, the data structure and lookup algorithm also
have to be more complicated
REFERENCING ENVIRONMENT of a statement at run time is the
set of active bindings
A referencing environment corresponds to a collection of scopes
that are examined (in order) to find a binding
SCOPE RULES determine that collection and its order
BINDING RULES determine which instance of a scope should be
used to resolve references when calling a procedure that was
passed as a parameter
• it govern the binding of referencing environments to formal procedures
ALIASING
• What are aliases good for? (consider uses of FORTRAN
equivalence)
• space saving - modern data allocation methods are
better
• multiple representations - unions are better
• linked data structures - legit
• Also, aliases arise in parameter passing as an unfortunate
side effect
• Euclid scope rules are designed to prevent this
OVERLOADING
• some overloading happens in almost all languages
• integer + v. real +
• read and write in Pascal
• function return in Pascal
• some languages get into overloading in a big way
• Ada
• C++
It's worth distinguishing between some closely related concepts
• overloaded functions - two different things with the same name; in C++
• overload norm
int norm (int a){return a>0 ? a : -a;)
complex norm (complex c ) { // ...
• polymorphic functions -- one thing that works in more then one way
• in Modula-2: function min (A : array of integer); …
• in Smalltalk
It's worth distinguishing between some closely related
concepts (2)
• generic functions (modules, etc.) - a syntactic template that
can be instantiated in more than one way at compile time
• via macro processors in C++
• built-in in C++
• in Clu
• in Ada
A language that is easy to compile often leads to
• a language that is easy to understand
• more good compilers on more machines (compare Pascal and Ada!)
• better (faster) code
• fewer compiler bugs
• smaller, cheaper, faster compilers
• better diagnostics
McGrath, Mike (2017). C++ Programming. In Easy Steps Limited.
Perkins, Benjamin (2016). Beginning Visual C# 2015 programming.
WroxSteve, Tale (2016). C++.
Chopra, R. (2015). Principles of Programming Languages. New Delhi: I.K. International
Publishing.
Kumar, Sachin (2015).Principles of programming Languages. S. K. Kataria& Sons.
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]