Hello, Swift Community.
The review of SE-0339: Module Aliasing for Disambiguation, begins now and runs through January 31st, 2022.
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. When emailing me directly, please keep the proposal link at the top of the message and put "SE-0339" somewhere 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/master/process.md
Thanks for helping make Swift a better language.
John McCall
Review Manager
10 Likes
SDGGiesbrecht
(Jeremy David Giesbrecht)
2
Seems mostly straightforward.
My only question is how it stacks. What happens if someone attempts to alias a module that has already been aliased lower down (deliberately or accidentally)?
1 Like
clayellis
(Clay Ellis)
3
I didnât see it mentioned specifically, but I assume that if a module name that didnât exist was used in moduleAliases, package resolution would fail? (e.g. moduleAliases: [âUtilsâ: âGarbageâ])
1 Like
lukasa
(Cory Benfield)
4
I am also curious about @SDGGiesbrecht's question.
A related concern that the proposal doesn't seem to flag is that this doesn't affect evolution. It remains the case that adding new modules can introduce clashes where they did not exist before, and cause build breakages. Module aliases need to be applied at the scope where they cause a conflict, and that is never going to be within the package that added the new module. So projects like NIO continue to need to namespace any new targets they add.
3 Likes
ebg
5
Is this possible to use independent of SwiftPM?
I can answer this one. Yes, the SwiftPM support fundamentally just turns into command-line flags to the compiler, and the Detailed Design section describes how those command-line flags work.
elsh
(Ellie Shin)
7
If there are multiple aliases specified for a module, it will throw an error during dependency resolution and fail to build. If a module has been aliased lower down, there shouldn't be a need to alias it again at the top level.
1 Like
elsh
(Ellie Shin)
8
The module Utils needs to exist to be aliased as Garbage. The new name Garbage should be a new unique name that does not conflict with any of the existing module names in the dependency graph.
1 Like
clayellis
(Clay Ellis)
9
I meant specifically if there wasnât a module named Garbage but you were trying to give it an alias.
elsh
(Ellie Shin)
10
Yes. You can pass -module-alias existing_name=new_name directly to swiftc.
1 Like
elsh
(Ellie Shin)
11
In such case, it will throw an error that no such module exists for aliasing.
clayellis
(Clay Ellis)
12
As expected, right. Does that need to be called out in the proposal?
elsh
(Ellie Shin)
13
Yes, will add that to the detailed design for the SwiftPM section.
1 Like
elsh
(Ellie Shin)
14
If a library package adds a new module within the package, it will need to use a non-conflicting name. Even if a package uses a namespace for its targets, a conflict can still occur at the top-level and module aliases can be applied to resolve the conflict.
SDGGiesbrecht
(Jeremy David Giesbrecht)
15
Let me give an example of what I mean. Imagine the following desired package graph, where every module is different:
MyPackage
Gaming
Sound (moduleAliases: [Utils: SoundUtils])
Utils
Utils
Music
Sound (moduleAliases: [Utils: SoundUtils])
Utils
Utils
With a standard dependency declaration, âMyPackageâ would have two clashing âSoundUtilsâ and at least two clashing âUtilsâ modules. What should it specify in moduleAliases for one or both of its dependencies in order to resolve the problem?
1 Like
Perhaps MyPackage ought to be able to set moduleAliases: [Sound: GamingSound, SoundUtils: GamingSoundUtils, Utils: GamingUtils] on its Gaming dependency, and then those would be substituted into the module aliases of Gaming's own dependencies.
SDGGiesbrecht
(Jeremy David Giesbrecht)
17
That was my intuition as a user too. But the proposal does not describe the intent in this scenario, and the PR appears to blindly collect a flat dictionary from the graph, basically with mergeâbyâoverwrite. Given that the resolver still suffers from a nonâdeterministic order of traversal in some parts of the code, I am not confident that it is even possible to predict the resulting module name with the pull requestâs implementation. It does not need to be actually fixed before the review is accepted, but it would be good to have the intent clarified first.
1 Like
elsh
(Ellie Shin)
18
That's a good example; we should allow an override at the scope where a conflict occurs then. Will update the proposal and implementation to reflect this.
Zollerboy1
(Josef Zoller)
19
The proposal also doesn't say, what happens if I want to alias a module that is a direct dependency. E.g. if I have the following package graph:
MyPackage
Sound
Utils
Music
Utils
And a target in my package has neither the Sound nor the Music module as a dependency, but both Utils modules. How would I write that?
let package = Package(
name: "MyPackage",
dependencies: [
.package(url: "https://.../Sound.git", from: "..."),
.package(url: "https://.../Music.git", from: "...")
],
products: [
.executable(name: "MyPackage", targets: ["MyPackage"])
],
targets: [
.executableTarget(
name: "App",
dependencies: [
.product(name: "Utils", package: "Sound"),
// .product(name: "Utils", moduleAliases: ["Utils": "MusicUtils"], package: "Music")
// or
// .product(name: "MusicUtils", moduleAliases: ["Utils": "MusicUtils"], package: "Music")
// ?
]
)
]
)
Also, just a minor criticism of the proposal text: currently the example package manifests included in the text are written in a weird mixture of JSON and Swift or something like that. It would probably be better to write them in normal Swift code, just how they would be written in a real package (also the *s around the moduleAliases parameters surprised me a bit when I first read them, I think it's better to leave them out).
2 Likes
elsh
(Ellie Shin)
20
For direct dependencies, you'd write
.product(name: "Utils", moduleAliases: ["Utils": "MusicUtils"], package: "Music"),
.product(name: "Utils", moduleAliases: ["Utils": "SoundUtils"], package: "Sound")
The proposal will be updated with the above scenario along with the format suggestion.