/*:#localized(key: "WhereAsyncLetRunsOut")
 # Where `async let` runs out

 `async let` starts a child task immediately and lets you `await` its value later.
 It's perfect when you know exactly how many things you're launching.
 */
//#-editable-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

// Simulate loading + calibrating one captured frame.
// Returns the frame's average brightness. The sleep stands in for the
// real work of reading the file and calibrating it.
func processFrame(_ index: Int) async -> Double {
    try? await Task.sleep(for: .milliseconds(500))
    return Double(index) * 1.5   // pretend this is the frame's brightness
}

Task {
    async let red   = processFrame(1)
    async let green = processFrame(2)
    async let blue  = processFrame(3)

    let total = await red + green + blue
    print("Three-channel stack: \(total)")
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "WhereAsyncLetRunsOut-2")
 Three channels, three `async let` lines. But how would you write this for tonight's
 8 frames, or tomorrow's 200? You can't
 type out `async let frame1`, `async let frame2`, ... up to a number you won't know
 until runtime. `async let` binds each child to a **named variable in your source
 code**, so the count is fixed when you write it. The moment the count is dynamic
 (driven by an array, a file listing, a user's selection), you've outgrown it.

 **A task group** is a scope that lets you add a *variable* number of child tasks
 in a loop, then collect their results as they finish. It's `async let` with the
 count lifted out of your source and into your data.

 [Previous](@previous)  |  page 2 of 9  |  [Next: Fanning Out with withTaskGroup](@next)
 */
