Skip to content

Instantly share code, notes, and snippets.

@oleganza
Created June 25, 2015 13:32
Show Gist options
  • Save oleganza/488405657685ed80df0d to your computer and use it in GitHub Desktop.
Save oleganza/488405657685ed80df0d to your computer and use it in GitHub Desktop.
Async Swift with explicit Promises
// Before
func makeSandwich(completionHandler: (result:Sandwich)->Void)

// After
async func makeSandwich() -> Sandwich

// Informally equivalent to:
func makeSandwich() -> Promise<Sandwich>
async func cutBread() -> Bread
async func cutCheese() -> Cheese
async func cutHam() -> Ham
async func cutTomato() -> Vegetable

async func makeSandwichSerially() -> Sandwich {
    let bread  = await cutBread()
    let cheese = await cutCheese()
    let ham    = await cutHam()
    let tomato = await cutTomato()
    return Sandwich([bread, cheese, ham, tomato])
}

async func makeSandwichInParallel() -> Sandwich {
    let bread  = cutBread() // -> Promise<Bread>
    let cheese = cutCheese()
    let ham    = cutHam()
    let tomato = cutTomato()
    // Wait for all components after all operations have been launched
    return Sandwich([await bread, 
                     await cheese, 
                     await ham, 
                     await tomato])
}

// Using a loop:

async func makeSandwichSerially() -> Sandwich {
    var components:[Ingredient] = []
    for ingredient in ingredients {
        components.append(await prepareIngredient(ingredient))
    }
    return Sandwich(components)
}

async func makeSandwichSerially() -> Sandwich {
    var pieces:[Promise<Ingredient>] = []
    for ingredient in ingredients {
        pieces.append(prepareIngredient(ingredient))
    }
    return Sandwich(pieces.map{ await $0 })
}

With error handling

// Before
func makeSandwich(completionHandler: (result:Sandwich?, error:ErrorType?)->Void)

// After
async func makeSandwich() throws -> Sandwich

// Informally equivalent to:
func makeSandwich() -> ThrowingPromise<Sandwich>
async func cutBread() throws -> Bread
async func cutCheese() throws -> Cheese
async func cutHam() throws -> Ham
async func cutTomato() throws -> Vegetable

async func makeSandwichSerially() throws -> Sandwich {
    let bread  = await try cutBread()
    let cheese = await try cutCheese()
    let ham    = await try cutHam()
    let tomato = await try cutTomato()
    return Sandwich([bread, cheese, ham, tomato])
}

async func makeSandwichInParallel() throws -> Sandwich {
    let bread  = cutBread() // -> ThrowingPromise<Bread>
    let cheese = cutCheese()
    let ham    = cutHam()
    let tomato = cutTomato()
    // if bread failed, function returns ignoring other errors
    return Sandwich([await try bread, await try cheese, await try ham, await try tomato])
}

// Using a loop:

async func makeSandwichSerially() -> Sandwich {
    var pieces:[Ingredient] = []
    for ingredient in ingredients {
        pieces.append(await try prepareIngredient(ingredient))
    }
    return Sandwich(pieces)
}

// Definition of await-as-a-function
func await(Promise<T>) -> T

async func makeSandwichSerially() -> Sandwich {
    var pieces:[Promise<Ingredient>] = []
    for ingredient in ingredients {
        pieces.append(prepareIngredient(ingredient))
    }
    return Sandwich(pieces.map(await))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment