/*:#localized(key: "OneTaskAtATime")
 # An actor lets in one task at a time

 First, the problem one more time. Here's the shape of the bug from the chapter
 [Concurrency Hazards](Concurrency%20Hazards.playgroundchapter/Overview), in its
 simplest form. A plain class holds a balance, and many concurrent deposits race
 on it:

 ```swift
 final class UnsafeLedger {
     var balance = 0

     func deposit(_ amount: Int) {
         balance += amount   // read, add, write (not atomic)
     }
 }
 ```

 That `balance += amount` is really *three* steps: read the current value, add
 to it, write it back. If two tasks read `0` at the same time, both write `1`,
 and one deposit is lost. Run a thousand concurrent deposits and you rarely get
 `1000`.

 In Swift 6, if you actually try to share that `UnsafeLedger` across concurrent
 tasks, **the compiler stops you**: a plain mutable class isn't safe to share,
 so it won't compile. That's the compiler pointing you at the right tool. The
 tool is an actor.

 An **actor** is a reference type, like a class, whose mutable state can only be
 touched by **one task at a time**. The actor serializes every access to its own
 state, so the read-add-write above can never overlap. Swap `class` for `actor`
 (and, while we're tightening things up, mark `balance` as `private(set)` so
 only the actor's own methods can change it; outside code can still read it):

 ```swift
 actor Ledger {
     private(set) var balance = 0

     func deposit(_ amount: Int) {
         balance += amount
     }
 }
 ```

 That's the whole fix. The `deposit` calls are now automatically serialized:
 while one task is inside `deposit`, every other task has to wait its turn. No
 queue to set up, nothing to remember. Let's hammer it with a thousand
 concurrent deposits using a task group (from the chapter [Task Groups](Task%20Groups.playgroundchapter/Overview)).
 */
//#-editable-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

actor Ledger {
    private(set) var balance = 0

    func deposit(_ amount: Int) {
        balance += amount
    }
}

let ledger = Ledger()

Task {
    await withTaskGroup(of: Void.self) { group in
        for _ in 1...1_000 {
            group.addTask {
                await ledger.deposit(1)
            }
        }
    }
    print("Final balance: \(await ledger.balance)")
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "OneTaskAtATime-2")
 **Watch it run:** the final balance is **`1000`. Every time.** Run it again
 and again; it never drifts. The thousand deposits all landed. Compare that to
 the class version, which loses updates unpredictably. The actor turned a race
 into a guarantee, and you didn't write a single lock.

 * callout(Try it): Bump the loop to `1...10_000` deposits. Does the final
 balance still come out exactly right every run?

 > This differs from the serial-queue fix earlier in the book.
 > There you *chose* to route every access through one queue, and nothing forced
 > you to be consistent; one stray direct access reintroduced the race. An actor
 > makes that protection part of the type. There is no way to reach `balance`
 > that skips the serialization, and the compiler checks it for you.

 [Previous](@previous)  |  page 2 of 7  |  [Next: Actor Isolation](@next)
 */
