@main: Type-Based Program Execution

@compnerd — I took a look at this previous thread on entry points so that I could understand the different things at play, and as you describe there, there seem to be two dimensions of platform-specific differences at work.

On the one hand, there's a difference in the kinds of arguments that are available to an entry point, like the typical argument count and vector, the Windows-specific HINSTACE, and the auxiliary vector on Linux. Some of these we provide right now as globally available properties through the stdlib's CommandLine type, and the proposal calls out a future direction of letting libraries define main as a (argc: Int, argv: ...) -> Int function instead of a nullary one. So for the other platform-specific values we could provide access to them in one, or preferably both, of those locations.

On the other hand, Windows apps have a distinction between how GUI and console apps are launched based on whether you provide a wmain or wWinMain entry point, which isn't specifically addressed in the proposal. I see a couple different ways we could go about handling this:

  1. We could expand the allowed static methods that a type can provide to include windowsMain() and/or windowsMain(argc: Int, argv: ...). If the @main designated type provides one of these, then the compiler would generate a wWinMain entry point instead of the default wmain.

  2. We could allow parameters on the @main attribute, so that you could write something like this, which would look for a main(console: Bool) or main(console: Bool, argc: Int, argv: ...) method:

    @main(console: false)
    struct MyApp: Application {
         // ...
    }
    

If the libraries that provide @main-supporting application-root protocols generally support either GUI or console apps, but not really both, #1 would seem like an appropriate solution. If we anticipate that libraries will want to support both kinds of development (which seems unlikely to me), then #2 might make more sense. #1 would still work in the second case, however — the library would only need to supply different protocols for console and GUI apps.

One issue with #2 is that it would look like things are more flexible than they are, since this is borrowing a bit of the way property wrappers work with wrappedValue. It would be a further extension of this syntax to support arbitrary library-defined parameters on the @main attribute.

What do you think of these as potential future extensions of the @main approach? Is this a correct summary of the platform-specific issues we need to address?

If we were to eventually adopt extension #1, you could add the following extension to your swift-win32 library. Then you could use the plain @main attribute on your SwiftApplicationDelegate type in your HelloSwift example.

extension AppDelegate {
    public static func windowsMain(
        _ argc: Int32,
        _ argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>
    ) -> Int32 {
        ApplicationMain(argc, argv, nil, self)
    }
}