[swift-evolution] Yet Another Take on Swift Sub-modules

Jean-Daniel mailing at xenonium.com
Sat Mar 4 08:12:59 CST 2017


> Le 3 mars 2017 à 23:21, Matthew Johnson via swift-evolution <swift-evolution at swift.org> a écrit :
> 
>> 
>> On Mar 3, 2017, at 9:24 AM, Karim Nassar via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> 
>> I’ve read through the last couple of Swift (sub)Module proposals put forward, and since my particular use-cases for a sub-module solution seemed to be under-served by them, I’ve decided to write up my thoughts on the matter to prompt discussion. 
>> 
>> Perhaps my use-cases are outliers, and my approach will be deemed naive by the community… I’m happy to learn better ways of doing things in Swift, and welcome any thoughts, criticism, or illumination related to these ideas.
>> 
>> I’m including the write-up below, but it’s also available as a gist: https://gist.github.com/anonymous/9806f4274f1e13860670d6e059be5dce
>> 
>>>> 
>> # Sub-modules
>> 
>> A sub-module solution in Swift should have the following properties:
>> 
>> * Extremely light-weight
>> * Low API surface area
>> * Adopt progressive disclosure
>> * Integrate with Access Control features to enable a level of encapsulation & hiding between the Module and File level
>> * Be permeable when desired
>> 
>> ## Discussion
>> 
>> As we get deeper into building real applications & frameworks with Swift, we begin to realize that having a way to express relationships between types is desireable.  Currently, Swift only allows us to express these relationships at two levels, the Module and the File. 
>> 
>> The Module boundary is acceptable for small, focused frameworks, while the File boundary is acceptable for small, focused Types, but both levels can be unweildy when dealing with certain cases where a cluster of internally related types needs to know about each other but may only want to publish a narrow set of APIs to the surrounding code, or in large complex applications which are necessarily structured as a single Module. In these cases, we wind up with large monolithic Modules or (even worse) large monolithic Files.
>> 
>> I have seen this proliferation of Huge Sprawling Files (HSFs) in my own code, and seek a way to combat this rising tide.
>> 
>> ## Goals 
>> 
>> It is a goal of this proposal to:
>> 
>> * Suggest a mechanism for organizing code between the Module and File levels that is as lightweight and low-friction as possible
>> * Provide mechanisms for authors to create both "hard" and "soft" API boundaries between the Module and File levels of their code
>> 
>> ## Anti-Goals
>> 
>> It is not a goal of this proposal to:
>> 
>> * Move Swift away from filesystem-based organization
>> * Significantly alter the current Access Control philosophy of Swift
>> 
>> ## Proposal Notes
>> 
>> Please take the following proposal wholely as a Straw-Man... I would be equally satisfied with any solution which meets the critera described at the top of this document.
>> 
>> Unless specified otherwise, all spellings proposed below are to be considered straw-men, and merely illustrative of the concepts.
>> 
>> ## Proposed Solution
>> 
>> Two things are clear to me after using Swift and following the Swift Evolution list since their respective publications:
>> 
>> 1. Swift has a preference for file-based organization
>> 2. Vocal Swift Users dislike `fileprivate` and want to revert to Swift2-style `private`
>> 
>> Because of #1, this proposal does not seek to change Swift's inherent file-system organization, and instead will expand on it.
>> 
>> Since I personally fall into the camp described by #2, and most of the community response to this has been "Lets wait to deal with that until sub-modules", I'm making this proposal assuming that solving that quagmire is in-scope for this propsoal.
>> 
>> ### Changes to Access Control Modifiers
>> 
>> As part of this proposal, I suggest the following changes to Swift 3's Access Control modifiers:
>> 
>> * Revert `private` to Swift 2's meaning: "hidden outside the file"
>> * Remove `fileprivate` as redundant
>> 
>> This is potentially a source-breaking change. However, it is interesting to note that this change is **not** required for the following proposal to function.
>> 
>> Changes that *are* necessary are:
>> 
>> * Change the spelling of `internal` to `module` (making `module` the new default)
>> * Introduce a new modifier `internal` to mean "Internal to the current sub-module and its child-sub-modules”
> 
> Can you give concrete examples of use cases where a descendent submodule needs access to symbols declared by an ancestor?  I gave some thought to this when drafting my proposal and came to the conclusion that this runs against the grain of layering and is likely to be a bad idea in practice.  If there are use cases I didn’t consider I am very interested in learning about them.
> 
>> 
>> These changes are *not* source-breaking because the new `internal` modifier acts exactly as the old `internal` modifier unless it is used within a sub-module. The specific spelling of this new `internal` modifier is necessary to maintain backwards source compatibility.
>> 
>> The new `module` modifier allows authors to make APIs permeable between sub-modules while still hidden outside the owning Module if desired.
>> 
>> All other Access Control modifiers behave the same as they currently do irrespective of sub-module boundaries, so:
>> 
>> * `public` => Visible outside the Module
>> * `open` => Sub-classable outside the Module
>> 
>> ### Making a Sub-module
>> 
>> To create a sub-module within a Module (or sub-module) is simple: The author creates a directory, and places a "sub-module declaration file" within the directory:
>> 
>> ```
>> //  __submodule.swift
> 
> Why the double underscore prefix?  To make it sort to the top in a file browser?
> 
> Is this file allowed to have any Swift code?  Or is it limited to submodule-related declarations only?  If the latter, why not use an extension such as `.submodule` or `.swiftmodule` to differentiate it from ordinary Swift files and allow the submodule to be named by the name of this file?
> 
>> //  MyModule
>> 
>> submodule SubA
>> 
>> ```
>> 
>> Then any files within that directory are part of the sub-module:
>> 
>> ```
>> //  Foo.swift
>> //  MyModule.SubA
>> 
>> struct Foo {
>>   private var mine: Bool
>>   internal var sub: Bool
>>   module var mod: Bool
>> }
>> 
>> public struct Bar {
>>   module var mod: Bool
>>   public var pub: Bool
>> }
>> 
>> ```
>> 
>> This creates a sub-module called "SubA" within the module "MyModule". All files within the directory in which this file appears are understood to be contained by this sub-module.
>> 
>> If in the future we choose to add additional complexity (versioning, #availability, etc) to the sub-module syntax, the sub-module declaration gives a natural home for this configuration.
>> 
>> It's important to note some benefits of this approach:
>> 
>> * Using the "special file" means that not all Directories are automatically submodules
>> * Any given source file may only be a member of 1 submodule at a time
>> * Use of filesystem structure to denote sub-modules plays nicely with source control
>> * The sub-module structure is instantly clear whether using an IDE (which can be taught to parse the `__submodule.swift` files to decorate the UI), or simple text-editor (assuming a convention of naming the Directory the same as the sub-module, which is a linter problem)
> 
> If we’re going to use the file system to organize submodules this seems like a reasonable approach.  It allows larger submodules to have folder hierarchies within them and also creates a central location for submodule-related declarations.
> 
> A primary flaw I see in this approach is that Xcode is the dominant IDE for Swift and the way Xcode handles files is not conducive to file-system organization.  I really detest the way Xcode handles this and would vastly prefer that it simply reflected the physical file system hierarchy but I don’t think that will change any time soon.  On the other hand maybe a file system based submodule system in Swift would motivate the Xcode team to better reflect the physical file system organization.

I quite love how Xcode allow me to group my source files as I want without having to move them around.
This is specially useful when working with languages that support relative #include "". Moving an header in an other group don’t break the code.

Moreover, if you want to create a folder for each group in Xcode, you can perfectly do that too as Xcode allows you to define a different path for each group. So I don’t see how it would prevent using submodule.





-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170304/6f028c4b/attachment.html>


More information about the swift-evolution mailing list