SE-0281: @main: Type-Based Program Entry Points

Hi Ben,

Yep, I explicitly acknowledged the points in the "alternatives considered" section. My point is that:

@main
class Foo : Thing {} 

is very terse and isn't well precedented in Swift. We tend to use more verbose names for things that have global impact on your process, because there is no need to huffman encode them into a short name, and more explicit names help googleability.

I agree with you that main.swift is currently used, but I expect that this feature (SE-0281) will kill it off main.swift quite quickly - so I don't see the importance of it over the long run. I also don't see a particular benefit to follow the C convention here - what exactly does it make better in context?

-Chris

2 Likes

While it will replace main.swift for projects that rely on framework that provide a main Type, I don't think it is going to kill main.swift, unless you plan to replace the Swift iconic Hello World

print("Hello World")

by this new one ;-) :

@main
class HelloWorld {
  static fun main() {
    print("Hello World")
  }
}
3 Likes

A search on GitHub for main.swift shows a lot of them (a majority?) would not benefit at all from the @main feature proposed here. I doubt very much this feature will replace main.swift in the general case.

Some are whole programs within a single file. Some are setting up routes for Vapor and then launching the server. Some are just printing "hello world". Some are initializing a few things before calling UIApplicationMain(). Some appears to be small experiments to test parts of the language.

Many programs out there aren't using a framework. Of those that do, not all frameworks are structured in a way where a framework-supplied main should be the first thing running, or can be reasonably attached to a user-supplied type.

3 Likes

My point is that [terse example] is very terse and isn't well precedented in Swift

The terseness seems fine to me aesthetically (possibly the unresolvable root of this disagreement?). And "not very well precedented in swift" is just untrue. I think what you mean is that while precedented, it defies other precedents. Another possible interpretation – saying "ah this isn't the entry point this is an attribute marking the class that has the entry point so it's not precedented" – would be splitting hairs.

But extra words add nothing here. Googling main swift currently googles you straight to "What is the entry point of swift code execution?" on Stack Overflow. The idea adding application to the front means anyone glancing at a short program or hunting a long program will find the code easier to read/search/understand by it's presence is not credible to me.

1 Like

To be fair, the single file issue is not at question, as it doesn't have to be named main.swift and needs to stay in place for scripting purposes. It's whether multi-file programs would switch from file naming to attribute use that's at question.

Some are setting up routes for Vapor and then launching the server. Some are just printing "hello world". Some are initializing a few things before calling UIApplicationMain() . Some appears to be small experiments to test parts of the language.

None of these seem incompatible with Chris' prediction that main.swift usage (distinct from single-file) will fade stylistically over time.

If we extend this feature later to give the framework control over the exact entry point(s) generated, as @compnerd and others have advocated for, then this feature could eventually grow to have a use case beyond application entry points tooβ€”in addition to a POSIX-style main or Windows-style WinMain, it could also be conceivably deployed to generate a DllMain or plugin entry point. So the word application strikes me as potentially overspecific in addition to being unnecessarily verbose.

9 Likes

As an alternative to an annotation, what about reserving a type name for the entry point of the program? This would mirror the way that protocol conformances work today, requiring you to either define a type that conforms to a protocol or define it with a typealias.

protocol MainEntryPoint {
  static func main() throws
}

// In module Module0
struct MagicName: MainEntryPoint {
  static func main() throws { ... }
}

// In module Module1
protocol ParsableCommand: Main {
  func run() throws
}

extension ParsableCommand {
  static func main() throws {
    let command = try decode()
    try command.run()
  }
}

struct Math: ParsableCommand {
    @Argument(help: "A group of integers to operate on.")
    var values: [Int]

    func run() throws {
        let result = values.reduce(0, +)
        print(result)
    }
}

// In module Module2
import Module1
public typealias MainEntryPoint = Math

// In module Module3
public typealias MagicName = Optional // Error: Optional does not conform to Swift. MainEntryPoint

This avoids annotations (which I'm generally kinda biased against), and follows the existing Swift restrictions on unique type names.

I would suggest MainEntryPoint and MainEntryPointProtocol, but just wanted to float up this alternative mechanism, as opposed to specific names

Thinking about it a bit more, we could provide a magic struct to extend to conform to a protocol.

// In module Module0
extension Module: RunnableAsMain {
  typealias MainEntryPoint = Math // Math conforms to MainEntryPointProtocol
}

This makes the mental model of the module as a swift type that needs to conform to a protocol to be runnable, with all the usual implications and support to reason about bugs in implementations.

That's true, but they do have a defined starting point (AppDelegate.swift), so one knows where to look anyway. Looking back, I was unclear on this. I'm not against renaming and consolidating @NSApplicationMain and @UIApplicationMain into one @main attribute. But I think in CLI projects, having a main.swift file makes the entry point clearer and easier to find, without being a hassle. This proposal is saying that it would eliminate needless main.swift files, when they simply call a library or custom type. But that's like two lines of code in a most-of-the-time pregenerated file. Trying to replace main.swift entry points seems like more trouble than it's worth.

Proposal Accepted

Please see the acceptance post in the Announcements section.

1 Like