Date post: | 05-Dec-2014 |
Category: |
Documents |
Upload: | eelco-visser |
View: | 2,366 times |
Download: | 3 times |
TI1220 2012-2013Concepts of Programming Languages
Eelco Visser / TU Delft
Lecture 2: Names, Bindings, and Scopes(Sebesta Chapter 5)
Outline
Messages from the lab
Names
Variables
Binding & binding time
Scope
Demo: Spoofax name binding language
Messages from the Lab
“There were not a lot of students at the lab. This of course is ok for the first week, but students should be told that they stand no chance of passing the graded assignments without the tutorials, or the exam without the graded assignments.”
“There are too many rooms for the number of students. Could you mention that they should start filling the rooms from the top, one by one and then move down as they fill up. Room 0.010 is quite unhandy for labs because of the cubicles.”
“WebLab of course does not work properly in Internet Explorer, we should tell students that.”
Email [email protected]: for personal questions about grades and [email protected]: for general questions about the [email protected]: for questions about the lab (addresses all student assistants)
PoliciesOur first response: did you ask this question at the lab?We’re closed in the weekend (in principle)Please report problems with WebLab immediately
Names (Identifiers)
Name Forms
[a-zA-Z][a-zA-Z0-9\_]* -> ID %% typical
"$" [a-zA-Z][a-zA-Z0-9\_]* -> PhpID [\$\@\%][a-zA-Z][a-zA-Z0-9\_]* -> PerlID "@" [a-zA-Z][a-zA-Z0-9\_]* -> RubyInstanceVar"@@" [a-zA-Z][a-zA-Z0-9\_]* -> RubyClassVar
Case Sensitive or Case Insensitive?
foobar == FooBar == FOOBAR ?
C-based languages: case sensitiveC convention: variable names only lower case letters Pascal: case insensitiveJava convention: CamelCase instead of under_scores
Special Words
keyword: identifier with special meaning in certain contexts
reserved word: special word that cannot be used as a name
Integer AppleInteger = 4
type
name
Fortran
Integer RealReal Integerpackage example;
class User { private String name; public String get_name { return name; }} Java
Variables
A program variable is an abstraction of a computer memory cell or collection of cells
machine language: absolute numeric address of data
assembly language: names for data
The attributes of a variable:NameAddressValueTypeLifetimeScope
the address of a variable is the machine memory address with which it is associated
def gcd(x: Long, y: Long): Long = if (y == 0) x else gcd(y, x % y)
each call to gcd creates new instances of x and y
alias: multiple variables accessing same memory location (more next week)
Type & Value
the type of a variable determines the range of values the variable can store and the set of
operations that are defined for values of the type
the value of a variable is the contents of the memory cell or cells associated with the variable
Binding & Binding Time
a binding is an association between an attribute and an entity
Example bindingsvariable to typevariable to valuefunction call to function definition
val msg = "Hello, " + "world!"
println(msg)
defining occurrencebinding
val variables cannot be rebound
applied occurrence
Binding Variable Identifiers
var greeting = "Hello, world!"
greeting = "Leave me alone, world!"
var variables can be rebound
rebinding
bindingdefining occurrence
Binding Variable Identifiers
def widthOfLength(s: String) = s.length.toString.length
val maxWidth = widthOfLength(longestLine)
bindingdefining occurrence
applied occurrence
Binding Function Identifiers
class ChecksumAccumulator { var sum = 0}
var acc = new ChecksumAccumulatorvar csa = new ChecksumAccumulator
acc.sum = 3csa = acc
binding
applied occurrence
defining occurrence
Binding Class Identifiers
class ChecksumAccumulator { var sum = 0}
var acc = new ChecksumAccumulatorvar csa = new ChecksumAccumulator
acc.sum = 3csa = acc
mutation
binding
rebinding
Rebinding vs Mutation
object foo { val foo : Int = 0 def foo(x : Int) = x + 1}
object bar { def bar() = foo.foo(foo.foo) }
variables, functions, objects are in separate name spaces
Namespaces
the time at which a binding takes places is called binding time
Example binding timeslanguage design timelanguage implementation timecompile timeload timelink timerun time
Type int in Cbound to range of possible values (e.g. 32 bit words)at language implementation time
Variable in Javabound to data typeat compile time
Variable in JavaScriptbound to data typeat run time
Symbolic Constants (C)
#include <stdio.h>#define LOWER 0 /* lower limit of table */#define UPPER 300 /* upper limit */#define STEP 20 /* step size */
/* print Fahrenheit-Celsius table */main() { int fahr; for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP) printf("%3d %6.1f\n", fahr, (5.0 / 9.0) * (fahr - 32));}
0 -17.8 20 -6.7 40 4.4 60 15.6 80 26.7100 37.8120 48.9140 60.0160 71.1180 82.2200 93.3220 104.4240 115.6260 126.7280 137.8300 148.9
compile-time binding of values
Typedefs (C)
typedef int Length;
Length len, maxlen;Length *lengths[];
typedef struct tnode *Treeptr;typedef struct tnode { /* the tree node: */ char *word; /* points to the text */ int count; /* number of occurrences */ struct tnode *left; /* left child */ struct tnode *right; /* right child */} Treenode;
Treeptr talloc(void) { return (Treeptr) malloc(sizeof(Treenode));}
compile-time binding of type name
Function Definitions and Calls (Scala)
def max(x: Int, y: Int): Int = { if (x > y) x else y}
max(3, 5)
function statically bound, argument values dynamically bound to formal parameters
Recursion (Scala)
def fib(x: Long): Long = if (x <= 0) 1 else if (x == 1) 1 else fib(x - 1) + fib(x - 2)
def gcd(x: Long, y: Long): Long = if (y == 0) x else gcd(y, x % y)
recursion requires dynamic binding of variables
a binding is static when it occurs before run time and remains
unchanged throughout execution
a binding is dynamic if it first occurs during run time or can change in the course of program execution
Function Expressions (JS)
// This function expression defines a function that squares its argument.// Note that we assign it to a variablevar square = function(x) { return x * x;}var q = square(10);function square(x) { return x * x; }
// Function expressions can include names, which is useful for recursion.var f = function fact(x) { if (x <= 1) return 1; else return x * fact(x - 1);};
// Function expressions can also be used as arguments to other functions:data.sort(function(a, b) { return a - b; });
// Function expressions are sometimes defined and immediately invoked:var tensquared = (function(x) { return x * x; }(10));
var square = function foo(x) {! return x * x;};
var z = square;
var r = z(10);
console.log(r);
function squareF(x) { return x * x; }
var q = squareF(10);
console.log(q);
var sq = squareF;
console.log("sq: " + sq);
console.log("sq(12): " + sq(12));
console.log(foo(3));
Type binding of variable
How specified? explicit vs implicit
When bound? static vs dynamic
an explicit declaration is a statement in a program that lists variable names and specifies that
they are a particular type
an implicit declaration is a means of associating variables with types
through default conventions, rather than declaration statements
In implicit typing, all constants, variables and arrays beginning with the letters I, J, K, L, M, or N are automatically taken to be of type INTEGER.
Constants, variables and arrays beginning with all other letters are assumed to be REAL.
Thus, with implicit typing, the variable COUNT is REAL whilst the variable KOUNT is an INTEGER.
Implicit typing can be overridden with explicit type declaration.
source: http://www.obliquity.com/computer/fortran/datatype.html
Fortran: static types, implicitly declared
$a : scalar (string or numeric value)#a : array%a : hash structure
Perl: implicitly declared with different name spaces
Variables and Expressions (C)
#include <stdio.h>
/* print Fahrenheit-Celsius table for fahr = 0, 20, ..., 300 */int main() { int fahr, celsius; int lower, upper, step; lower = 0; /* lower limit of temperature scale */ upper = 300; /* upper limit */ step = 20; /* step size */ fahr = lower; while (fahr <= upper) { celsius = 5 * (fahr - 32) / 9; printf("%d\t%d\n", fahr, celsius); fahr = fahr + step; } return 0;}
static types, explicitly declared
type inference: implicit type declaration using context
Languages with type inferenceMLHaskellOCamlF#ScalaVisual BASIC 9.0+Go
def widthOfLength(s: String) = s.length.toString.length
val lines = Source.fromFile(args(0)).getLines.toList
val longestLine = lines.reduceLeft( (a, b) => if (a.length > b.length) a else b)
val maxWidth = widthOfLength(longestLine)
Scala: static types, inferred from context
dynamic type binding: variable is bound to type when it is assigned a value
Languages with dynamic type bindingRubyJavaScriptLispSchemePythonPHP
Variable Declaration (JS)
var i;var sum;
var i, sum;
var message = "hello";var i = 0, j = 0, k = 0;
for(var i = 0; i < 10; i++) console.log(i);for(var i = 0, j=10; i < 10; i++,j--) console.log(i*j);for(var p in o) console.log(p);
var i = 10;i = "ten";
list = [10.2, 3.5];list = 47;
JavaScript: dynamic type binding
Ruby
all variables are references
all data are objects (there is only one type)
any variable can reference an object
Disadvantages of dynamic typing
programs are less reliable: types not checked by compiler
cost of checking types at run time
next week: storage bindings and lifetime
Scope
the scope of a variable is the range of statements in which the variable is visible
a variable is local in a program unit or block if it is declared there
the non-local variables are those that are visible but not declared in a program
unit
class ChecksumAccumulator { private var sum = 0 def add(b: Byte): Unit = { sum += b } def checksum(): Int = { return ~(sum & 0xFF) + 1 }}
Scala: variable sum is non-local for methods add and checksum
static scoping: scope of variable can be statically determined
nested scopes: Ada, JavaScript, Scheme, Scala, F#, Python
non-nested scopes: C-based languages
function big() { function sub1() { var x = 7; sub2(); } function sub2() { var y = x; } var x = 3; sub1();}
static scoping in JavaScript
Variable Scope (JS)
var scope = "global"; // Declare a global variablefunction checkscope() { var scope = "local"; // Declare a local variable with the same name return scope; // Return the local value, not the global one}checkscope() // => "local"
Variable Scope (JS)
scope = "global"; // Declare a global variable, even without var.function checkscope2() { scope = "local"; // Oops! We just changed the global variable. myscope = "local"; // This implicitly declares a new global variable. return [ scope, myscope ]; // Return two values.}checkscope2() // => ["local", "local"]: has side effects!
scope // => "local": global variable has changed.myscope // => "local": global namespace cluttered up.
Nested Functions (JS)
var scope = "global scope"; // A global variablefunction checkscope() { var scope = "local scope"; // A local variable function nested() { var scope = "nested scope"; // A nested scope of local variables return scope; // Return the value in scope here } return nested();}checkscope() // => "nested scope"
function hypotenuse(a, b) { function square(x) { return x * x; } return Math.sqrt(square(a) + square(b));}
if (list[i] < list[j]) { int temp; temp = list[i]; list[i] = list[j]; list[j] = temp;}
block: sections in which allocation of storage for variables is allocated
void sub() { int count; ... while (...) { int count; count++; ... } ...}Java and C# do not allow
shadowing of variables
def printMultiTable() { var i = 1 // only i in scope here while (i <= 10) { var j = 1 // both i and j in scope here while (j <= 10) { val prod = (i * j).toString // i, j, and prod in scope here var k = prod.length // i, j, prod, and k in scope here while (k < 4) { print(" ") k += 1 } print(prod) j += 1 } // i and j still in scope; prod and k out of scope println() i += 1 } // i still in scope; j, prod, and k out of scope}
block scope in Scala:order of declaration
matters
Function Scope and Hoisting (JS)
function test(o) { var i = 0; // i is defined throughout function if (typeof o == "object") { var j = 0; // j is defined everywhere, not just block for ( var k = 0; k < 10; k++) { // k is defined everywhere, not just loop console.log(k); // print numbers 0 through 9 } console.log(k); // k is still defined: prints 10 } console.log(j); // j is defined, but may not be initialized}
JavaScript does not have block scope!
Use Before Declaration
var scope = "global";function f() { console.log(scope); // Prints "undefined", not "global" var scope = "local"; // Variable initialized here, but defined everywhere console.log(scope); // Prints "local"}
function f() { var scope; // Local variable is declared at the top of the function console.log(scope); // It exists here, but still has "undefined" value scope = "local"; // Now we initialize it and give it a value console.log(scope); // And here it has the value we expect}
let val name1 = expression1 ... val namen = expressionnin expressionend;
let val top = a + b val bottom = c - din top / bottomend;
let binding in ML
Describing Static Name Binding Rules
module names
imports include/Delftnamespaces Module Entity Propertyrules
Module(x, _) : defines Module x scopes Entity Entity(x, _) : defines Entity x of type Type(x) scopes Property Property(x, t) : defines Property x of type t Type(x) : refers to Entity x refers to Entity "String" refers to Entity "Int"
NaBL: Spoofax Name Binding Language
module blog
imports user entity BlogPosting { name : String poster : User body : String blog : Blog title : String}
entity Blog { title : String author : Blog}
entity User { name : String}
Reading & Programming in Week 2
Reading: Sebesta
Chapter 5: Names, Bindings, Scopes
Week 3: Dynamic Binding & Storage
WebLab:
C tutorialJavaScript tutorialMore Scala tutorial
Grammars and regular expressions