umka-lang icon indicating copy to clipboard operation
umka-lang copied to clipboard

Implement closures

Open vtereshkov opened this issue 4 years ago • 1 comments

Allow capturing variables from outer function's stack/heap frame:

fn adder(x: int): fn (y: int): int {
    return fn (y: int): int {
        return x + y
    }
}

fn main() {
    add5 := adder(5)
    a := add5(7)
    printf(repr(a) + '\n')  // 12
}

This would require changing the internal representation of functions from

int64_t entry;

to

struct
{
    int64_t entry;
    void *upvalues;
}

The API functions umkaCall() and umkaGetFunc() will also have to be changed.

vtereshkov avatar Jul 01 '21 12:07 vtereshkov

Beware of extremely perverse cases like the following one taken from Crafting Interpreters.

fun outer() {
  var x = "value";
  fun middle() {
    fun inner() {
      print x;
    }

    print "create inner closure";
    return inner;
  }

  print "return from outer";
  return middle;
}

var mid = outer();
var in = mid();
in();

vtereshkov avatar Jul 01 '21 21:07 vtereshkov

The example from Crafting Interpreters rewritten in Umka:

fn outer(): fn(): fn() {
  x := "value"
  
  middle := fn(): fn() |x| {
    inner := fn() |x| {
      printf("%s\n", x)
    }

    printf("create inner closure\n")
    return inner
  }

  printf("return from outer\n")
  return middle
}

fn main() {
  mid := outer()
  inn := mid()
  inn()
}

Output:

return from outer
create inner closure
value

vtereshkov avatar Jul 05 '23 08:07 vtereshkov