Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closures #12

Open
liquidev opened this issue Dec 29, 2021 · 0 comments
Open

Closures #12

liquidev opened this issue Dec 29, 2021 · 0 comments
Labels
feature This issue is related to implementing a major feature of the compiler. language feature Adding a new feature into the language.

Comments

@liquidev
Copy link
Member

Closures are a pretty essential feature for things like iterator adapters. There are a few considerations in mind when it comes to closures:

  • How do we make them not require the heap? I'd rather have closures be quite cheap in cost.
    • One possible approach is to take Rust's compiler-generated opaque type idea, where to use closures, you need to create a generic parameter that allows for any type to be passed, or optionally, use trait pointers.
  • I think we should allow for explicitly preventing closures from storing pointers, as it often causes more trouble than it's worth (lifetime hell). Or maybe create two constraints, fun and fun rc, the first of which permits any variables but acts like a pointer (can only be used as an argument and not stored anywhere), the second only permits functions that do not capture external variables by reference (ie. the latter can be stored in an rc).
    • I'm not a fan of fun rc because, with its primary purpose being storage in rcs, rc fun rc (Float): Float does not look very pretty. Maybe rc fun (Float): Float should imply that the inner fun is rc?
  • There needs to be a way of specifying that variables should be moved into the closure, explicitly.

Here's a preview of what such closure constraints would look like.

fun map[T, U, F](sequence: Seq[T], fn: F): Seq[U]
where
   F: fun (T): U

   var result = Seq[U].with_capacity(sequence.len)
   for element in sequence.iter_move
      val mapped = fn(element)
      result.push(mapped)
   result

The above defines a function map, which accepts the argument fn, whose type is F which must satisfy fun (T): U. Now, each function satisfies the fun (T): U constraint, but all values that are only known to have said constraint act like pointers in terms of lifetimes, so we can work with them, pass them by argument, return them, but not store them in external locations.

Additionally, we need to define syntax for creating closures. I propose the following:

# No return type and no arguments:
var my_function = fun
  print("x")

# With an argument with an explicit type:
var my_function = fun (x: Float)
  print(x + 2)

# With an argument with an explicit parameter type _and_ return type:
var my_function = fun (x: Float): Float
  print(x + 2)
  x + 2

# With inferred parameter type, single-line version using `->`:
[1, 2, 3]
  .iter_move
  .for_each(fun (x) -> print(x))

# With inferred parameter and return type, again single-line version:
[1, 2, 3]
  .iter_move
  .map(fun (x) -> x + 2)

Moving values into the closure is done by adding the move keyword after fun, like fun move -> x (a closure without arguments, moving all captured variables, in this case x, into its body).

Indentation-based syntax does not play well with this version of creating closures:

do_stuff(fun ()
  print("abc")
)

leaving an ugly trailing parenthesis at the end. Thus I also propose a syntactic sugar to implement later:

do_stuff() do ()
  print("abc")

Dubbed "infix do blocks", it moves the last closure argument out of the parentheses, into a separate block outside of the function, introduced through an infix operator. Alternatively, to not overload the do keyword with two meanings, fun could also be used.

do_stuff() fun ()
  print("abc")
@liquidev liquidev added language feature Adding a new feature into the language. feature This issue is related to implementing a major feature of the compiler. labels Jan 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature This issue is related to implementing a major feature of the compiler. language feature Adding a new feature into the language.
Projects
None yet
Development

No branches or pull requests

1 participant