Why is the `{}` syntax called `closure expression` in swift?

It's a bit splitting hairs, but no closure record is formed by the compiler until a call site is seen. While this can be seen as merely an optimization for local functions in isolation, it's really necessary for it to work this way for mutually-recursive local functions to work practically with the reference counting and strict initialization semantics Swift requires. If you have:

func outer(x: inout T) {
  var y = 0
  func foo() {
    print(x)
    bar()
  }
  func bar() {
    print(y)
    foo()
  }

  bar()
}

Then for foo and bar to be able to call each other, it wouldn't work out if the foo or bar declarations immediately formed a closure record at the declaration site, because they need to be able to access each other's captured variables x and y. If foo captured only x at its declaration site, then bar captured only y at its call site, neither would have enough context to invoke the other. And if you did this in the somewhat more traditional way of having foo and bar capture each other's closures, you would have both a reference cycle, causing a leak if naively implemented with reference counting, and a circular initialization problem building the mutually-recursive closure objects. Furthermore, access to the inout argument x must be restricted to nonescaping call sites in order not to violate the lifetime restriction on x. To maximize the expressivity of local functions and closures, and also coincidentally optimize immediate call sites and recursive local functions to reduce the number of closure allocations necessary, it turns out to be simpler to defer the closure formation for local functions to their actual use site—when you invoke bar immediately, or pass it as a function value, only then does the compiler crawl through its transitive dependencies to figure out what context needs to be captured along with the function to call it.

10 Likes