Interaction between async main and async overloads

Right now, we can make the static main function of an @main type async to easily "upgrade" the top-level context to async. Unfortunately, overload resolution currently prefers the synchronous main. As an example, the following program will currently print Bar:

protocol Bar { }

extension Bar {
  static func main() {
    print("Bar")
  }
}

@main
struct Foo: Bar {
  static func main() async {
    print("Foo")
  }
}

The issue is that in the presence of a synchronous main method (which most @main oriented protocols provide) I haven't yet found a way to get Swift to prefer the asynchronous main (mostly I've tried various combinations of marking the method unavailable, but I've only been able to make this work when I mark the original implementation unavailable, which doesn't work for existing libraries). This means the only way to get an asynchronous context and conform to one of these protocols (in my case, argument-parser's ParsableCommand) is to use something like DispatchSemaphore, which may have other consequences.

What do folks think about inverting the overload resolution rule only for @main? Meaning, if a type ends up with a synchronous and asynchronous main defined on it, the asynchronous variant will be preferred for purposes of fulfilling the @main requirement. Is it already too late?

Update:
My current workaround looks something like this:

public static func main() throws {
  Task {
    do {
      try await main()
      exit(0)
    } catch {
      exit(error.convertToStatusCode)
    }
  }
  dispatchMain()
}

Note: There is an ongoing amendment review for async main semantics, but I believe this issue to be outside of the scope of that amendment.

Just popping in to confirm your belief. That proposal does not change how the overloads are handled.

Terms of Service

Privacy Policy

Cookie Policy