alanrgan / rust-interpreter

0 stars 0 forks source link

Closures referencing outside variables #9

Closed alanrgan closed 7 years ago

alanrgan commented 7 years ago
fn foo(a: int, f: Func<int, bool>) : bool {
     for i in range [0..a] {
          if !f(a) {
                return false;
          }
     }
     return true;
}

let x: list = [1..11];
// 'x' should be available in the inner function scope here
foo(a, fn(i: int) : bool { return x[i] < 8; });
alanrgan commented 7 years ago

Variable values are moved only in the case that they do not conflict with any of the parameter names

let x: list = [1..11];
foo(a, fn(x: int) : bool { return x[i] < 8; }); // error; list x is not moved here
alanrgan commented 7 years ago

It should be the case that any value referenced from the containing function should be available in the closure after the containing function exits.

fn foo() : Func<_,_> {
     let a: int = 3;
     return fn { print(a); };
}  // normally 'a' would go out of scope here
foo()(); // should print '3'

In essence, any variables that are closed over should be 'bundled' with the closure as a pointer.

let a: int = 3;
let z: Func<_,_> = fn { print(a); };
z(); // should print 3
a = 4;
z(); // should print 4

However, variables that are closed over should not override any preexisting variables:

fn foo() : Func<_,_> {
    let b: int = 3;
    return fn { print(b); };
}

let b: int = 2;
let z: Func<_,_> = foo();
z(); // should print '3'
print(b); // should print 2

Notice that while the returned function does close over a variable named 'b', the 'b' in the returned scope should not be overwritten. This means that closed variables cannot simply be propagated upward through scopes.

Recap

  1. Closures should extend the lifetime of variables it encloses
  2. Closures should store pointers to these variables and should be responsive to any change and be able to make changes to these variables themselves.
  3. Enclosed variables may have name conflicts with variables defined in other scopes. Closures should not overwrite the other variable in this case.
alanrgan commented 7 years ago

Closures have been implemented for the most part. Since Piper (this language's working name) is an object oriented language, closures do not store any state.

Thus,

let a: int = 3;
let z: Func<_,_> = fn { print(a); };
z(); // should print 3
a = 4;
z(); // prints 3

Closures are still consistent:

fn foo() : Func<_,_> {
    let b: int = 3;
    return fn { print(b); };
}

let b: int = 2;
let z: Func<_,_> = foo();
z(); // prints '3'
print(b); // prints '2'