Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add transformed operation to Future #4051

Merged
merged 1 commit into from
Sep 25, 2024

Conversation

mats-stripe
Copy link
Collaborator

Summary

This adds a new operation to our fork of Future, transformed(with:). This will allow us to apply a simple synchronous transform to a Promise value.

Note

Our implementation of Future is quoted to being taken from Swift by Sundell. This implementation of transformed(with:) also comes from the same source.

Here is the author's blog post with some more details.

At its core, this unlocks basic functionally for transforming a Promise value:

let promise = Promise<Int>(value: 42)

let doubledFuture = promise.transformed { value in
    return value * 2
}

doubledFuture.observe { result in
    switch result {
    case .success(let value):
        print("Transformed value: \(value)") // Transformed value: 84
    case .failure(let error):
        print("Error: \(error)")
    }
}

At a practical level, this unlocks type erasure of Future values. Here's a simple example:

protocol Animal {
    var name: String { get }
}

struct Dog: Animal {
    let name: String
}

struct Cat: Animal {
    let name: String
}

func getRandomAnimal() -> Future<Animal> {
    let randomNumber = Int.random(in: 0...1)
    if randomNumber == 0 {
        return getRandomDog() // Cannot convert value of type 'Future<Dog>' to closure result type 'Future<any Animal>'
    } else {
        return getRandomCat()
            .transformed { $0 as Animal } // Works!
    }
}

func getRandomDog() -> Future<Dog> {
    let promise = Promise<Dog>()
    promise.resolve(with: Dog(name: "Buddy"))
    return promise
}

func getRandomCat() -> Future<Cat> {
    let promise = Promise<Cat>()
    promise.resolve(with: Cat(name: "Whiskers"))
    return promise
}

In this scenario, the getRandomAnimal() function would get a compile error:

Cannot convert value of type 'Future<Dog>' to closure result type 'Future<any Animal>'

However, we fix that error bellow using .transformed { $0 as Animal }

Motivation

Unlocks type erasure of Future values.

Testing

Added a bunch of unit tests for Async.swift!

Changelog

N/a - these methods are all behind a @_spi(STP) class.

@mats-stripe mats-stripe requested review from a team as code owners September 24, 2024 20:14
Copy link
Collaborator

@porter-stripe porter-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ hopefully we can get FC to use Swift async/await in the future!

@mats-stripe mats-stripe merged commit 4cee7ab into master Sep 25, 2024
5 checks passed
@mats-stripe mats-stripe deleted the mats/add_transform_to_async_future branch September 25, 2024 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants