Static property wrappers and strict concurrency in 5.10

I have similar concerns.

One way to make a type Sendable is indeed to protect its internal state with a lock. This is one use cases of the recent [Pitch] Synchronous Mutual Exclusion Lock (cc @Alejandro).

I have also tried to make my mutex a property wrapper, hoping that the language would show some awareness for well-behaved programs. But it does not work very well:

@Mutex var value = 1
run { // an @escaping @Sendable closure
  // Error: Mutation of captured var 'value'
  // in concurrently-executing code
  value = 2
  // OK
  $value.withLock { $0 = 2 }
}
run {
  print(
}

I use this a lot in tests of asynchronous-but-not-async methods (similar to DispatchQueue.async):

@MainActor // for waitForExpectations
func test_that_value_is_2() {
  let expectation = self.expectation(description: "")
  @Mutex var value: Int? = nil
  giveMeTwoEventually { n in // an @escaping @Sendable closure
    $value.withLock { $0 = n }
    expectation.fulfill()
  }
  waitForExpectations(timeout: 1)
  XCTAssertEqual(value, 2)
}

Without strict concurrency checks, the tests is easier to write, obviously:

// Without strict checks
func test_that_value_is_2() {
  let expectation = self.expectation(description: "")
  var value: Int?
  giveMeTwoEventually { n in
    value = n
    expectation.fulfill()
  }
  waitForExpectations(timeout: 1)
  XCTAssertEqual(value, 2)
}
2 Likes