Closures
Today: Linked Stacks
Where are we now?
What is a Closure?
var f = fun(x) {
print(x);
};
f(1);
var x = 1;
var f = fun() {
print(x);
};
f();
Output: 1
var x = 1;
var f = fun() {
x = 2;
};
print(x)
var g = fun(h) {
h();
}
print(x)
g(f);
print(x);
Output: 1
Outputs: �1�1�2
Challenge: Managing Scopes
A closure may refer to the value of variable from a scope that has been popped from the stack
Scope’s frame may live longer than the the single execution of the scope’s code
What do we do?
var f = 0;
{
var x = 1;
f = fun() {
print(x);
x = x + 1;
};
}
f();
f();
f();
Output:
1
2
3
Statements: Inference Rules
Expressions: Inference Rules
Integer
Constant
Variable
Reference
Unary
Minus
Statements: Inference Rules
{
var x = 1;
var x = 2;
}
Statements: Inference Rules
Update
Challenge: Managing Scopes
A closure may refer to the value of variable from a scope that has been popped from the stack
Scope’s frame may live longer than the the single execution of the scope’s code
What do we do?
var f = 0;
{
var x = 1;
f = fun() {
print(x);
x = x + 1;
};
}
f();
f();
f();
Output:
1
2
3
Closures versus “Functions”
void f() {
int x = 1;
printf(“%d\n”, x);
x = x + 1;
}
void f() {
static int x = 1;
printf(“%d\n”, x);
x = x + 1;
}
int x = 1;
void f() {
printf(“%d\n”, x);
x = x + 1;
}
void main(...) {
f(); f(); f();
}
var f = 0;
{
var x = 1;
f = fun() {
print(x);
x = x + 1;
};
}
f();
f();
f();
Output:
1
1
3
Closures versus “Functions” (C++ Attempt)
void f() {
int x = 1;
printf(“%d\n”, x);
x = x + 1;
}
void f() {
static int x = 1;
printf(“%d\n”, x);
x = x + 1;
}
int f_x = 1;
void f() {
printf(“%d\n”, f_x);
f_x = f_x + 1;
}
void main(...) {
f(); f(); f();
}
Output:
1
1
1
Output:
1
2
3
Output:
1
2
3
Challenge: Managing Scopes
var f = 0;
{
var x = 1;
f = fun() {
print(x);
x = x + 1;
};
}
f();
f();
f();
Output:
1
2
3
var g = fun() {
var x = 1;
var f = fun() {
print(x);
x = x + 1;
};
return f;
};
g()();
g()();
g()();
Output:
1
1
1
Challenge: Managing Scopes
A closure may refer to the value of variable from a scope that has been popped from the stack
Scope’s frame may live longer than the the single execution of the scope’s code
What do we do?
var f = 0;
{
var x = 1;
f = fun() {
print(x);
x = x + 1;
};
}
f();
f();
f();
Output:
1
2
3
Allocate frames in the heap!
Closures versus “Functions”
struct FClosure {
int x;
FClosure() : x() { }
int f() {
printf(“%d\n”, this.x);
this.x = this.x + 1;
}
};
FClosure* g() { return new FClosure();}
int main(...)
{
g()->f(); g()->f(); g()->f();
}
var g = fun() {
var x = 1;
var f = fun() {
print(x);
x = x + 1;
};
return f;
};
g()();
g()();
g()();
These are Automation (plus more)
f = lambda x, y : x + y
var f = function(x, y) {
return x + y;
}
var f = (x, y) => {
return x + y;
}
auto f = [](int x, int y) {
return x + y;
};
BinaryOperator<int> f = (int x, int y) -> {
return x + y;
};
Python
C++
Java
Javascript
Extending IMP with Closures
Extending IMP with Closures
Add Closures: Grammar
(call closure)
Extending IMP with Closures
Linked Stacks
1: var x = 1;
2: var y = 2;
3: {
4: var x = 3;
5: y = 4;
6: }
Line | Frame Pointer | Heap (h) |
1 | | |
2 | | |
3 | | |
4 | | |
5 | | |
6 | | “ ” |
Linked Stacks
1: var x = 1;
2: var y = 2;
3: {
4: var x = 3;
5: y = 4;
6: }
Line | Frame Pointer | Heap (h) |
1 | 100 | {100 : {x : 200}, � 200 : 1} |
2 | 100 | |
3 | 108 | |
4 | 108 | |
5 | 108 | |
6 | 100 | |
Linked Stacks
1: var x = 1;
2: var y = 2;
3: {
4: var x = 3;
5: y = 4;
6: }
Line | Frame Pointer | Heap (h) |
1 | 100 | {100 : {x : 200}, � 200 : 1} |
2 | 100 | {100 : {x : 200, y : 208}, � 200 : 1, 208 : 2} |
3 | 108 | |
4 | 108 | |
5 | 108 | |
6 | 100 | |
Linked Stacks
1: var x = 1;
2: var y = 2;
3: {
4: var x = 3;
5: y = 4;
6: }
Line | Frame Pointer | Heap (h) |
1 | 100 | {100 : {x : 200}, � 200 : 1} |
2 | 100 | {100 : {x : 200, y : 208}, � 200 : 1, 208 : 2} |
3 | 108 | {100 : {x : 200, y : 208}, 108 : {p : 100}, � 200 : 1, 208 : 2} |
4 | 108 | |
5 | 108 | |
6 | 100 | |
Linked Stacks
1: var x = 1;
2: var y = 2;
3: {
4: var x = 3;
5: y = 4;
6: }
Line | Frame Pointer | Heap (h) |
1 | 100 | {100 : {x : 200}, � 200 : 1} |
2 | 100 | {100 : {x : 200, y : 208}, � 200 : 1, 208 : 2} |
3 | 108 | {100 : {x : 200, y : 208}, 108 : {p : 100}, � 200 : 1, 208 : 2} |
4 | 108 | {100 : {x : 200, y : 208}, 108 : {p : 100, x : 216}, 200 : 1, 208 : 2, 216 : 3} |
5 | 108 | |
6 | 100 | |
Linked Stacks
1: var x = 1;
2: var y = 2;
3: {
4: var x = 3;
5: y = 4;
6: }
Line | Frame Pointer | Heap (h) |
1 | 100 | {100 : {x : 200}, � 200 : 1} |
2 | 100 | {100 : {x : 200, y : 208}, � 200 : 1, 208 : 2} |
3 | 108 | {100 : {x : 200, y : 208}, 108 : {p : 100}, � 200 : 1, 208 : 2} |
4 | 108 | {100 : {x : 200, y : 208}, 108 : {p : 100, x : 216}, 200 : 1, 208 : 2, 216 : 3} |
5 | 108 | {100 : {x : 200, y : 224}, 108 : {p : 100, x : 216}, 200 : 1, 208 : 2, 216 : 3, 224 : 4} |
6 | 100 | |
Linked Stacks
1: var x = 1;
2: var y = 2;
3: {
4: var x = 3;
5: y = 4;
6: }
Line | Frame Pointer | Heap (h) |
1 | 100 | {100 : {x : 200}, � 200 : 1} |
2 | 100 | {100 : {x : 200, y : 208}, � 200 : 1, 208 : 2} |
3 | 108 | {100 : {x : 200, y : 208}, 108 : {p : 100}, � 200 : 1, 208 : 2} |
4 | 108 | {100 : {x : 200, y : 208}, 108 : {p : 100, x : 216}, 200 : 1, 208 : 2, 216 : 3} |
5 | 108 | {100 : {x : 200, y : 224}, 108 : {p : 100, x : 216}, 200 : 1, 208 : 2, 216 : 3, 224 : 4} |
6 | 100 | “ ” |
Frames, Heaps, Linked Stacks, and Closures
Evaluation Relations (with heaps and stacks)
Evaluation Relations (with linked stacks)
Expressions: Inference Rules
Integer
Constant
Variable
Reference
Unary
Minus
Lookup
Expressions: Inference Rules
Integer
Constant
Variable
Reference
Unary
Minus
Inference Rules: Declaration
In-place update
Inference Rules: Assignment
Update
Inference Rules: Block Scope
Extending IMP with Closures
Inference Rules: Closure Creation (Declaration)
Inference Rules: Closure Creation
Managing Scope (Revisited)
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | |
3 | 208 | |
7 | 208 | |
8 | 200 | |
9 | 200 | |
10 | 200 | |
Managing Scope (Revisited)
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {f : 100}} |
3 | 208 | |
7 | 208 | |
8 | 200 | |
9 | 200 | |
10 | 200 | |
Managing Scope (Revisited)
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | |
8 | 200 | |
9 | 200 | |
10 | 200 | |
Managing Scope (Revisited)
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
8 | 200 | |
9 | 200 | |
10 | 200 | |
Managing Scope (Revisited)
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
8 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
9 | 200 | |
10 | 200 | |
Managing Scope (Revisited)
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
8 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
9 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124:1, 132:2 200 : {f : 116}, 208 : {p : 200, x : 132} , 212 : {p : 208, y: 124} } |
10 | 200 | |
Managing Scope (Revisited)
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
8 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
9 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124:1, 132:2 200 : {f : 116}, 208 : {p : 200, x : 132} , 212 : {p : 208, y: 124} } |
10 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 1, 132:2, 140: 2, 148: 3 200 : {f : 116}, 208 : {p : 208, x : 132} }, 212 : {p : 208, y : 124} , 216 : {p : 208, y : 140} } |
Inference Rules: Closure Execution
x Evaluates to a closure
E evaluates to a value
Create a new frame
Evaluate body of closure
Managing Scope (Revisited)
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
8 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {f : 116}, 208 : {p : 200, x : 108} } |
9 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 2, 200 : {f : 116}, 208 : {p : 200, x : 124} , 212 : {p : 208} } |
10 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 2, 132:3 200 : {f : 116}, 208 : {p : 208, x : 132} }, 212 : {p : 208} , 216 : {208} } |
1: var f = 0;
2: {
3: var x = 1;
4: f = fun() {
5: print(x);
6: x = x + y;
7: };
8: var y = 2;
9: }
10: f(1);
11: f(2);