Skip to content

Implement Closure #2753

Description

@HerrCai0907

Feature suggestion

#798 and #1240 has discussed lots of thing about closure, but maybe there are some outdated information.
So I want to start to discuss it in some new page.

Project State

  1. function object will be compiled as static object in data area.
  2. function object store function index in table and null env.

High Level Requirement For Closure

  1. Every function object from the same FunctionExpression will have different env.
  2. When call function object, function can use (read / write) the variable in env and upper function env.
  3. (Optional) If function is not a closure function, supporting closure has no or small influence this function in the perspective of code size and spend.

What should we do to support closure

For better code review, I think maybe we can support it step by step. I will post everything we need to implement closure. Please correct my mistakes and omissions.

let upper_function = () => {
  let variable_in_upper_function: i32 = 0;
  let current_function = () => {
    let variable_in_current_function: i32 = 0; // used in lower function.
    variable_in_upper_function = 1; // variable declared in upper function.
    let lower_function = () => {
      variable_in_current_function = 2;
    }
  }
)

code gen

semantic

  • we need a way in compiler to create / modify class definition.
  • analyze which function expression should enable closure supporting.
  • analyze which local variable is used in lower function.
  • analyze which identifier is declared in upper function. (already support in resolver.ts)

Activity

  1. alienself commented on Mar 15, 2024

    @alienself

    Any progress on this @HerrCai0907 ?

    I personally truly wish we had threads and closure support, I am looking at the AssemblyScript since a few years now, waiting for those features to land to be able to use it more often and I feel like I am not alone.

    This project is super exciting and yet we are missing core features for the language to be more broadly used.

  2. sasq64 commented on Oct 17, 2024

    @sasq64
    Contributor

    Has there been talk of not implementing full closures, but enough "syntactic sugar" to make lambdas useful?

    Basically look at old java or c++ and do something like;

    • Define an "internal" interface Function { call(...any[]): any; }
    • Make lambdas convert to an object implementing this interface as needed
    • Create fields for every variable in the outer scope that is accessed by the lambda, and assigned them by value

    So something like (pseudo-code warning);

    class Array {
      map(function: Function): Array {
       // ...
       function.call(...)
      }
    }  
      
    let a: u32 = 1
    let b = new MyObj()
    
    let newList = someList.map(item -> item + a + b.get())

    Where the compiler transforms the last line to;

    class UnNameableFunction implements Function {
       a: u32
       b: myObj
       call(item: u32): u32) {
         return item + a + b.get()
       }
    }
    
    temp = new UnNameableFunction()
    temp.a = a
    temp.b = b
    let newList = someList.map(temp)   
  3. HerrCai0907 commented on Oct 19, 2024

    @HerrCai0907
    MemberAuthor

    It need more work than I expected. Closure is a big challenge since it need lots of compiler internal feature to support. e.g. create a temporary object / class definition in local context as the definition of closure object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions