SE-0317: Async Let

But that is the whole point, this isn't like a let. Two major differences pointed out upthread:

actor SomeActor {
  // async let creates and runs its body in a new task, so its initializer requires sendability for any captured values.
  func g(x : NSString) { ... }
  func test1(x : NSString) {
    let a = g(x: x)    // Ok 
    async let b = g(x: x)+asyncthing() // not ok, because of Sendable check.
  }

  // async let runs its body in a new task, so actor self promotion happens.
  var someString : NSString

   func test2() {
     let a= g(x: someNSString) // everything is ok

     // Error, cannot refer to non-sendable property on isolated actor reference "self".
     async let b = g(x: someNSString)+asyncthing()
   }
}

Furthermore, the promotion of actor self from a "nonisolated Self" to an "isolated Self" introduces implicit suspend points given the proposed semantics, which is a huge concern from a logic correctness perspective:

func makeString() async -> String {... }
actor Actor2 {
   func oneThing() {...}
   func twoThing() -> String { ... }

   func test2() {
     oneThing()
     let a = twoThing() + await makeString() // everything is ok

     // compiles fine, but is NOT the same.
     oneThing()
     async let b = twoThing() + makeString()
   }
}

Note the footgun that just happened there. If you spell this out explicitly, you can see what happened, because this would not compile:

  // Error: cannot invoke doThing synchronously given a cross-task reference to actor 'self'.
  @Future let b = { doThing() + await makeString() }

You'd be required to spell it like this, which makes it clear what is going on:

@Future let b = { await self.doThing() + await makeString() }

However, the proposal doesn't achieve this, and claiming that "async let is like a let" makes it extremely difficult to understand these things. The proposed behavior would just silently and unexpectedly introduced a suspension point between oneThing() and twoThing(), undermining the goal of the actor proposal which requires marking to make suspensions something we can reason about.

The proposal is not at all like a let. This is a different beast, and the syntax it is eliminating is load bearing.

-Chris

7 Likes