Skip to content

Instantly share code, notes, and snippets.

@brennanMKE
Last active October 2, 2023 17:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brennanMKE/a9eb7f7563a754c2b877bc48805aab2d to your computer and use it in GitHub Desktop.
Save brennanMKE/a9eb7f7563a754c2b877bc48805aab2d to your computer and use it in GitHub Desktop.
Swinging Door: Reentrancy with an actor using Swift Concurrency

Swinging Door

This actor has 3 doors which can all be opened and closed. The open and close function will open or close all doors and also call the closure after each individual door has been modified. What happens if the open function has been called and the closure calls the close function?

Output:

Open All
🟦 πŸ”³ 🟩 πŸ”³ 🟨 πŸ”³
🟦 πŸ”² 🟩 πŸ”³ 🟨 πŸ”³
🟦 πŸ”² 🟩 πŸ”² 🟨 πŸ”³
🟦 πŸ”² 🟩 πŸ”² 🟨 πŸ”²
Close All
🟦 πŸ”² 🟩 πŸ”² 🟨 πŸ”²
🟦 πŸ”³ 🟩 πŸ”² 🟨 πŸ”²
🟦 πŸ”³ 🟩 πŸ”³ 🟨 πŸ”²
🟦 πŸ”³ 🟩 πŸ”³ 🟨 πŸ”³
/// Swift Concurrency and reentrancy.
///
/// What happens when the closures are called while the function is
/// still modifying the properties of the actor?
import SwiftUI
// What happens if the closure for opening calls the close function?
let closeWhileOpening = false
enum OpenClosed: CustomStringConvertible {
case open
case closed
var description: String {
switch self {
case .open:
"πŸ”²"
case .closed:
"πŸ”³"
}
}
}
actor SwingingDoor {
var blueDoor: OpenClosed = .closed
var greenDoor: OpenClosed = .closed
var yellowDoor: OpenClosed = .closed
func openAllDoors(closure: @escaping @Sendable () async -> Void) async {
blueDoor = .open
await closure()
greenDoor = .open
await closure()
yellowDoor = .open
await closure()
}
func closeAllDoors(closure: @escaping @Sendable () async -> Void) async {
blueDoor = .closed
await closure()
greenDoor = .closed
await closure()
yellowDoor = .closed
await closure()
}
}
let swingingDoor = SwingingDoor()
func logStatus(_ swingingDoor: SwingingDoor) async {
print("🟦 \(await swingingDoor.blueDoor) 🟩 \(await swingingDoor.greenDoor) 🟨 \(await swingingDoor.yellowDoor)")
}
Task {
print("Open All")
await logStatus(swingingDoor)
await swingingDoor.openAllDoors {
await logStatus(swingingDoor)
if closeWhileOpening {
await swingingDoor.closeAllDoors {
// do nothing
}
}
}
print("Close All")
await logStatus(swingingDoor)
await swingingDoor.closeAllDoors {
await logStatus(swingingDoor)
}
}
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
sleep(1)
PlaygroundPage.current.finishExecution()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment