The proposed approach hangs both on iOS and macOS (just not in unit tests executed in parallel), which is fascinating in its own right. See inline comments: ```swift @main struct BlockerApp: App { @State var count = 0 var body: some Scene { WindowGroup { VStack { Text("\(count)") Button("Increment") { // tapping on the button hangs the app count += blocking { 1 } // the closure is never called } } } } } func blocking<A>(_ ƒ: @escaping () async -> A) -> A { let semafore = DispatchSemaphore(value: 0) let got = Got<A>() Task.detached(priority: .high) { got.a = await ƒ() // gets as far as this line but ƒ is never called semafore.signal() } semafore.wait() return got.a! } private class Got<A> { var a: A? } ``` However, if we require that the closure is executed in another context, for example by annotating the parameter with a custom global actor, then this solution works on both macOS and iOS: ```swift @globalActor public actor BlockingActor { public static let shared = BlockingActor() } @available(*, deprecated, message: "For use only to allow incremental migration to structured concurrency") public func blocking<A>(_ ƒ: @BlockingActor @escaping () async -> A) -> A { let semaphore = DispatchSemaphore(value: 0) let got = Got<A>() Task(priority: .high) { got.a = await ƒ() semaphore.signal() } semaphore.wait() return got.a! } ``` Alas, a nested call would still cause a hang: ```swift count += blocking { blocking { // moving to the same executor, so we hang as before 1 } } ``` This, of course, is just a particular example of the fundamental reason that the use of any such API must be discouraged. Note, however, that we do already have quite a few existing APIs that are similarly discouraged, yet do exist for good reason. A particularly relevant example is the `sync` method of `DispatchQueue`, which will cause a hang in exactly the same way if you use it to schedule a task to wait for itself. In spite of this, `sync` method has been put to many a good use over the years.