Update to swift package init executable template

Hi all,

I've been working on some changes to swift package init --type executable to improve scalability and maintainability based on feedback from the SwiftPM community. If you're interested in the code you can check out the pull request.

Here's a breakdown of the proposed changes to the executable template:

Current

// ./Sources/MyPkg.swift
print("Hello, world!")

Proposed

// ./Sources/MyPkg/MyPkg.swift
@main
struct MyPkg {
    static func main() {
        print("Hello, world!")
    }
}
  • @main annotated struct: Replace top-level code with an @main annotated struct. This avoid issues with top-level variable initialization and provides a clear entry point.
  • Subfolder Structure: Move the source file into a subfolder within Sources. This anticipates the eventual need for multiple targets, and avoids having to restructure the project's layout to add another target.

This change also brings the executable and tool template types more in line with each other, as --type tool already used an @main annotated struct.

Templates are a balance between simplicity and scalability/maintainability, and the goal is to move towards a template that scales well without the need for refactoring. I'm interested in your feedback so please let me know what you think about these changes.

9 Likes

I don't have a strong opinion either way, but as brought up in the PR, we changed this not too long ago. I do think it is a significant churn for long-time users to have the templates change semi-regularly, so it would be good to figure out how we can avoid doing that for entirely subjective choices like these.

The first point, maybe, if we're confident the top-level constructs will never be fixed.

As to the second, it seems completely unnecessary to add yet another layer of indirection for a something that may never occur. Restructuring the file layout is trivial.

Should the main function be async throws, so that a user can insert try await calls without compiler errors?

5 Likes

If this issue is resolved, the problem you stated can be easily resolved by swift package add-target and there should be no need for a subdirectory.

From personal experience helping new folks get started with Swift, the recently updated templates cause quite a bit of friction. While I understand the intention of making the simple package look as simple as possible. The fact that when adding a new target in the manifest suddenly requires existing file to be moved around causes confusion.

I personally do think that we should settle this once and for all. As @NeoNacho said constantly changing the layout of the templates is causing a lot of unnecessary churn.

2 Likes

Thanks for this bug report. I've put up a draft fix for that issue up for discussion here: Move files when using `package add-target` on single target package by plemarquand · Pull Request #8413 · swiftlang/swift-package-manager · GitHub

However I still think modifying the template folder structure is beneficial since, as @FranzBusch mentioned, users will still have to restructure the layout if they manually add a target to the manifest.

I think this is a good change -- the magical top level code is confusing and touches on hairy aspects of the language...

It is quite unfortunate that there's so much ceremony with the @main. Even Java nowadays has it shorter, this is enough to have a main method in Java once JEP 445: Unnamed Classes and Instance Main Methods is accepted...

// java, not even a class or static necessary since JEP-445
void main() {
    System.out.println("Hello, World!");
}

but I think this is on the language to fix the @main complexity, and not on the package manager here. So overall I do welcome the move back to @main, it is more clear and less surprising and paves a way forward to keep simplifying the way @main works.

3 Likes