Async Initializers

Hi,

I setup swift-format today and got the error error: file contains invalid or unrecognized Swift syntax. for a lines containing init() async. I have included sample code below running from a fresh swift package init --type executable which runs fine on MacOS from the either the Terminal or Xcode but I didn't see any mention of async initializers in the Language Reference. I am wondering if this is a bug/bad practice and should be avoided or just not a full supported feature yet?

@main
struct AsyncInit {
    public static func main() async {
        print("main")
        _ = await Delayed()
        print("initialized")
    }   
}
struct Delayed {
    init() async {
        try! await Task.sleep(nanoseconds: 1_000_000_000)
        print("Delayed")
    }
}

Thanks in advance,
Zane

1 Like

I ran into this today and was hoping to avoid this:

@MainActor
struct MyPlugin {
    init() {
        Task {
            try await Task.sleep(until: .now + .seconds(5), clock: .continuous)
            // URLSession.shared... refresh token blah
        }
    }
}

// Call site
let plugin = await MyPlugin()
plugin.publisher.. pipe to SwiftUI blah

Switching to actors does have a concurrent initializer available:

actor MyActor {
    init() async throws {
        try await Task.sleep(until: .now + .seconds(5), clock: .continuous)
    }
}

// Call site
let myActor = try await MyActor()

If you look at the Swift core library, many container classes/structs offers initialization from network/filesystem. This is quite different from libraries in other languages. Such constructors might be convenient but it can also potentially block your thread for several seconds if there is a network access for example. In this case an asynchronous constructor makes sense.

It also makes me wonder why they didn't add read methods for the containers instead. Instead of doing everything in the constructor like reading and populate contents, why not have a read method. In this case it would have been easy to add a readAsync method. Instead the constructor only does the more basic initialization of the container that is pretty fast.

I'm not that convinced that everything should be done in the constructor in the standard library like it is today.