Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Introduction
Today we'll work on some review questions and exercises relating to names, bindings and scope. It's important that you
understand the difference between static and dynamic binding and scoping rules – as well as when it's appropriate to use
the stack or the heap for data storage.
The exam for this course will consist of a selection of questions from each week's lab (80%) and related questions which
help to tie different areas of programming languages together (20%). If you can answer these questions in the lab – you
can answer them in the exam! Remember – in these labs you aren't expected to know every single answer from memory
– sometimes it's best to do a little research / reading / re-reading of materials and come up with a great, and correct,
answer rather than just 'taking a stab' at the question and hoping you're right!
Review Questions
What symbols are legal or illegal for the name to start with (i.e. reserved prefixes).
Reserved words are better than keywords because reserved words cannot be redefined, whereas keywords CAN be
redefined. This may cause problems if, for example, you redefine a keyword to have an altered meaning, but this is not
widely documented public knowledge to the people using those keywords, who would (rightly) believe that the keywords
held their original meaning!
The r-value of a variable is the actual value held at the l-value's memory address.
4. Define binding and binding time. What are the different times that binding can take place in a
program? [Q7+8]
A binding is an association between an attribute and an entity, such as between a variable and its type of value, or
between an operation and a symbol. The time at which a binding takes place is called the binding time.
Bindings can take place at a number of different stages / times, such as at:
5. Define static binding and dynamic binding. Give one example of each. [Q9]
A binding is static is it first occurs before run time begins and remains unchanged throughout program execution. For
example, a constant may be defined as const int daysInWeek = 7; - the daysInWeek constant will have its type determined
at compilation and it will be statically fixed to being an int, with a specified value, as a specified (albeit relative) memory
address during compilation.
If the binding first occurs during run time or can change in the course of program execution, it is called dynamic
binding. For example, if a program declared (but did not instantiate) an array of objects, then asked the user to choose
[I]nteger or [F]loat, then depending on the choice made by the user at runtime the array could be instantiated as an
array of (for example) three objects of the desired type with either:
6. Define static, stack-dynamic, explicit heap-dynamic and implicit heap-dynamic variables. What
are the advantages and disadvantages of each? [Q12]
Static variables are those that are bound to memory cells before program execution begins, and remain bound to those
same memory cells until program execution terminates. Statically bound variables have several valuable applications in
programming - for example, globally accessible variables (global variables) are often used throughout the execution of a
program, thus making it necessary to have them bound to the same storage location during executions. However, the
disadvantage is that the type cannot be changed during runtime at all, ever!
Stack-dynamic variables are those whose storage bindings are created when their declaration statements are elaborated,
but whose types are not statically bound. The main advantage of Stack-dynamic variables are that, to be useful (at least
in most cases), recursive subprograms require some form of dynamic local storage so that each active copy of the
recursive subprogram has its own version of the local variables - this is made possible by stack-dynamic variables. The
main disadvantage of stack-dynamic variables, relative to static variables, is the runtime overhead of the dynamic
allocation and deallocation - and the possibly slower accesses because indirect addressing is required.
Explicit heap-dynamic variables are nameless (abstract) memory cells that are allocated and deallocated by explicit run-
time instructions written by the programmer. These variables, which are allocated from and deallocated back to the heap,
can only be referenced through pointer or reference variables. Advantages are that it makes it possible construct dynamic
structures such as linked lists and trees which can grow and shrink at runtime, and that we have full access to large
amounts of RAM on the target machine, which we cannot get via the stack. However, the downsides are the difficulty in
using pointer and reference variables correctly - failure to correctly allocate and deallocate memory can lead to memory
leaks!, and the complexity/time-cost of managing all these allocation and deallocations - this is a hidden cost that occurs
'behind the scenes' because heap management must take place by the operating system.
Implicit heap-dynamic variables are bound to heap storage only when they are assigned values. In fact, all their
attributes are bound every time they are assigned. For example, consider the following JavaScript assignment statement:
Regardless of whether the variable named highTemps was previously used in the program or what it was used for - it is
now an array of five numeric values.The advantage of such variables is that they have the highest degree of flexibility,
allowing highly generic code to be written without having to worry about explicit deallocation (they'll deallocate when
they go out of scope!). The disadvantages of implicit heap-dynamic variables include the overhead of maintaining the
dynamic attributes such as array subscript types and ranges, as well as some potential loss of error detection by the
compiler.
The referencing environment of a statement is the collection of all variables that are visible in the statement. In a static-
scoped language, this is the set of variables declared in its local scope plus the set of variables in any ancestor scopes
that are visible.
In such a language, the referencing environment 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 runtime. In other words - the
referencing environment is required so that we know what variables can be accessed from the current point in the code!
Problem Set
1. Which of the following identifier forms is most readable? Support your decision. [EX1]
SumOfSales
sumOfSales
sum_of_sales
SUMOFSALES
sum_of_sales is probably technically the most readable as each word is separated with an underscore, which makes it
almost as easy to read as plain English. However, sumOfSales is the most usable – because the starting lowercase value
tells us that we're dealing with a variable or object and not a class (which would start with a capital letter), and the lack
of underscores (which require shift + - to insert into text – i.e. a two-ley combo) mean that we don't have to perform the
key-combo everytime we want to write out the variable/object name.
2. Some programming languages are typeless. What are the obvious advantages and disadvantages
of having no types in a language? [EX2]
Advantages of typeless languages are that we don't have to work out what types will work together – the interpreter will
do it for us. Also, we can re-use variable names with different data types easily, i.e.
Disadvantages are that we may have to be a lot more careful in combining data of different types when we cannot
guarantee that the types are compatible, for example, multiplying a numeric value by a string would not throw an error
until runtime in a typeless language, while this would be caught automatically and far earlier at compile time in a
strongly typed language.
3. Assume the following JavaScript program was interpreted using static-scoping rules. What value of x
is displayed in function sub1? Under dynamic-scoping rules, what value of x is displayed in function
sub1? [EX7]
var x;
function sub1() { document.write("x = " + x + "<br />"); }
x = 5;
sub2();
def sub2():
global x; P2: x can be referenced but not assigned. y
a = 13; and z are local to sub1.
x = 15;
w = 17;
#P3
P3:
P4:
ITECH5403 Comparative Programming Languages
List all the variables, along with the program units where they are declared, that are visible at the points P1
through P4 assuming static scoping is used. You can use the following website to help answer this
question – but do remember the website won't be available in the exam!
http://www.pythontutor.com/visualize.html#mode=edit
Also, on the python tutor website, be sure to select Language: Python 3.3 from the drop-down (because
Python 2.x does not provide the nonlocal keyword) [EX9]
Given the following calling sequences and assuming that dynamic scoping is used, what variables are
visible during execution of the last subprogram activated? Include with each visible variable the name
of the unit where it is declared: [EX12]
6. Write a JavaScript script that has subprograms nested three deep and in which each nested
subprogram references variables defined in all of its enclosing subprograms. Use this link to help you
get started: http://javascript.info/tutorial/functions-declarations-and-expressions [EX3]
<!DOCTYPE html>
<html>
<head>
<script>
// Initial global variables in main referencing environment
var w = 0, x = 1, y = 2, z = 3;
function sub1() {
var x = 4; // Overwrite x with local copy
alert("In sub1 - w is: " + w + ", x is: " + x + ", y is: " + y + ", z is: " + z);
function sub2() {
var y = 5; // Overwrite y with local copy
alert("In sub2 - w is: " + w + ", x is: " + x + ", y is: " + y + ", z is: " + z);
function sub3() {
var z = 6; // Overwrite z with local copy
alert("In sub3 - w is: " + w + ", x is: " + x + ", y is: " + y + ", z is: " + z);
}
sub3(); // Call sub3 from within sub2
} // End of sub2
sub2(); // Call sub2 from within sub1
} // End of sub1
</script>
</head>
<body>
<h1>JavaScript Nested Functions / Closure Test</h1>
<button type="button" onclick="sub1()">Do Stuff!</button>
</body>
</html>
7. Using Code::Blocks or a similar IDE (Visual Studio etc.), create a new C project (NOT C++) that
declares a global int called x, and write a function that includes the following sequence of statements:
x = 21;
int x;
x = 42;
Run the program and explain the results. Rewrite the same code in C++ and Java and compare the
results. [EX5]
C example:
#include <stdio.h>
#include <stdlib.h>
void func() {
x = 21;
printf("After assignment in func, x address is: %p with value: %d\n", &x, x);
int x = 42;
printf("After local x dec'd in func, x address is: %p with value: %d\n", &x, x);
}
int main() {
printf("In main scope, x address is: %p with value: %d\n", &x, x);
func();
// Get a key then bail (used to keep the console window open)
getch();
return 0;
}
Variable gets hidden by variable with same name inside local scope of function. Memory addresses show that
these are distinct variables.
C++ Example:
#include <iostream>
#include <stdio.h>
using namespace std;
void func() {
x = 21;
printf("After assignment in func, x address is: %p with value: %d\n", &x, x);
int x = 42;
printf("After local x dec'd in func, x address is: %p with value: %d\n", &x, x);
}
int main() {
printf("In main scope, x address is: %p with value: %d\n", &x, x);
func();
// Get a key then bail (used to keep the console window open)
getchar();
return 0;
}
Same behaviour as in C!
Java example:
// Constructor must perform work otherwise declaration of 'int x' above must be static if
executed in 'main' method
public Main() {
System.out.println("In constructor, x address is: " + ((Object)x).hashCode() + "
with value: " + x);
func();
}
int x = 42;
System.out.println("After new x declared in func, x address is: " +
((Object)x).hashCode() + " with value: " + x);
Output:
In constructor to access class property x, address is: 0 with value: 0
After assignment in func, x address is: 21 with value: 21
After new x declared in func, x address is: 42 with value: 42
Same behaviour as in C! They all work in the same manner! I'm not entirely sure this is what we're meant to be
proving asides from that variable hiding works in local scopes…
8. Write three functions in C++: one that declares a large array statically, one that declares the same
large array on the stack, and one that creates (and frees!) the same large array on the heap. Call each
of the subprograms a large number of times (at least 100,000) and output the time required by each.
Explain the results. [EX7]
You can use the following code as the basis for your timer:
Answer:
#include <iostream>
#include <time.h>
void createStaticArray()
{
// 100,000 element static array of ints
static int foo[100000];
foo[0] = 123;
foo[99999] = 456;
int sum = foo[0] + foo[99999];
}
void createStackArray()
{
// 100,000 element static array of ints
int bar[100000];
void createHeapArray()
{
// 100,000 element static array of ints
int *baz = new int[1000000];
delete[] baz;
}
cout << "----- " << testName << " -----" << endl;
cout << "Start time : " << startTime << endl;
cout << "End time : " << endTime << endl;
cout << "Duration in Milliseconds: " << durationInMS << endl << endl;
}
int main()
{
// Static array test
startTime = clock();
for (int loop = 0; loop < 10000000; loop++)
{
createStaticArray();
}
printTimings("Static Array Test");
getchar();
return 0;
}
Look how quick the static array test is! 21ms! This is because the static array is only ever allocated once and then re-
used. However, this measurement might be off as the static array is allocated before we even start the main program
execution, because that's how static allocation works.
The stack array test is almost 290x slower than the static test it allocates the array each time, but stack allocation and
deallocation is fast!
The heap test takes the longest (1656x slower than static, and almost 6x slower than stack allocation) because it has to
dynamically allocate and deallocate tha large array on the heap each time, which is slower than via the stack (stack
deallocation is incredibly quick because we just 'pop' the stack to revert it to the previous state).