SE-0383: Deprecate `@UIApplicationMain` and `@NSApplicationMain`

Hello, Swift community!

The review of SE-0383: Deprecate @UIApplicationMain and @NSApplicationMain begins now and runs through January 16th, 2023.

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager by email. When contacting the review manager directly, please keep the proposal link at the top of the message and put "SE-0383" in the subject line.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  • What is your evaluation of the proposal?
  • Is the problem being addressed significant enough to warrant a change to Swift?
  • Does this proposal fit well with the feel and direction of Swift?
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at:

https://github.com/apple/swift-evolution/blob/main/process.md

Thank you,

John McCall
Review Manager

22 Likes

+1.

End of review.

4 Likes

For clarity, are there any corner cases where either @UIApplicationMain or @NSApplicationMain in a currently compiling project cannot be updated to use @main instead without other source changes?

5 Likes

Shouldn't

  • Use one of the hard coded framework-specific attributes @UIApplicationMain
  • or @NSApplicationMain Use the more general @main attribute

in the proposal be

  • Use one of the hard coded framework-specific attributes @UIApplicationMain or @NSApplicationMain
  • Use the more general @main attribute

?

1 Like

Thanks, I missed that in my editorial review. Fixed in the live document.

1 Like

Makes sense. It always felt weird to have framework specific attributes in the language. @main ftw :raised_hands:

+1

Being able to deprecate two framework-specific attributes in favor of a generalized language feature is a useful and satisfying simplification.

Two questions / comments:

The warning message

The warning message as written in the proposal is:
'@UIApplicationMain' is deprecated in Swift 5

But the warning message in the pull request seems to be:
'UIApplicationMain' is deprecated and will be removed in a future release; use '@main' instead

The latter message seems more informative and correct, especially since the warning in the proposal mentions this being deprecated in Swift 5, which is an earlier release than when the @main attribute is introduced.

Just want to confirm the latter warning message is what is intended and suggest updating the proposal with that message.

Upcoming feature identifier

Was adding an 'upcoming feature' identifier as per SE-0362 considered?

In this case, it would cause the warning to become an error prior to the release of Swift 6.

Since there can only be a single use of the existing framework-specific attributes allowed per app and the fix required to compile in Swift 6 is a simple mechanical change, it may not be worth the overhead of supporting an upcoming feature identifier.

But with the approval of SE-0362, I wonder if any proposal which introduces future source-breaking changes should either include an upcoming feature identifier or a brief rationale why one will not be provided. (This proposal is probably the most minimal case of a source breaking change possible.)

1 Like

It's good to get feedback like this about the implementation, and I don't want to suggest that it's in any way off-topic for review threads. As the review manager, though, I should clarify that the proposal is not actually proposing a specific implementation, and there's no expectation that the document reflects the current diagnostic text. All that matters as far as the accuracy of the proposal document goes is that a certain quality of implementation is possible.

1 Like

I'm certainly not aware of any such cases. I can expound upon the logic for the migration path, then perhaps you can catch any inconsistencies there:

Consider a Swift module that has adopted @UIApplicationMain or @NSApplicationMain. This must be done outside of a main.swift file, so we only have to consider library-style code. Further, the type declaration these attributes are attached to must:

  • Be a class
  • Be unique wrt further declarations annotated with any of the entrypoint attributes, including @main.
  • Conform to the corresponding application delegate protocol (which also requires it be a subclass of NSObject)

What does this all get us? It means existing code has to look something like this:

@UIApplicationMain
class MyDelegate: NSObject, UIApplicationDelegate { }

What can you change here? The base class could certainly be different (I often refine NSResponder instead myself), you can mark the class @objc, or final, or give it access control modifiers, or make it an actor instead.

All of these do not affect inheritance of the entrypoint. Notably, you cannot

  • Remove the application delegate protocol conformance
  • Change the class to a value type instead

Are there backwards deployment problems? Also no since the main entrypoint is emitted into client code - just like the synthetic entrypoints created for the framework-specific attributes.

Again, perhaps I'm missing something, but I would expect a counterexample here to be pretty gnarly. For example, one could go out of their way to declare a static func main() {} in their app delegate that, upon migration, would get automatically called instead of the main provided by an application delegate conformance:

@main // was @UIApplicationMain
actor AppDelegate: NSObject, NSApplicationDelegate {
  static func main() {
    fatalError("oops")
  }
}

They'd need to change the name of this function in addition to adopting the @main attribute to avoid the code exploding. This example would crash on launch, and a less contrived example wouldn't call UIApplicationMain or NSApplicationMain to set anything up, so I think the authors of such an implementation would catch it pretty quickly.

3 Likes

+1

An obviously correct step towards language simplification and platform independence.

Would there be a way to detect and warn about the edge case of a shadow main()?

I realize it would not be common but from a developer's perspective this could be a mysterious and difficult to diagnose issue:

A developer follows what seems like a simple fix-it: the compiler suggests the change @UIApplicationMain to @main. They possibly make this change in the process of correcting the various warnings that appear in a project with a new version of Swift and this change does not stand out as something that could have major consequences.

Then they recompile and run. Their app stops launching since their main() doesn't call UIApplicationMain(). The behavior appears like a crash on launch - the UI shows up briefly and disappears. Of course there is no crash, the app just exits, but that would be confusing as well.

If the developer isn't familiar with @main and exactly how it works it wouldn't be very clear at all what the problem is.

I think it would be useful for that edge case to be detected and display a warning. Or, at least, this edge case and how to fix it should be noted in the release notes.

2 Likes

SE-0383 has been accepted.

1 Like