<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I didn't expect submodules to be a part of the Swift 4 discussion. When it came up I was pleasantly surprised. I have been thinking about the design of a submodule system for quite a while but was planning to wait until it was clearly in scope to draft a proposal. Now that the topic has been introduced I decide to write down the design I've been thinking about, along with the motivation and goals that underly it. I understand submodules may not be in scope for Swift 4 but wanted to contribute this design while the discussion is fresh in everyone's mind.</div><div class=""><br class=""></div><div class="">I am including the contents of the proposal below. You can also find it on Github: <a href="https://github.com/anandabits/swift-evolution/blob/scope-based-submodules/proposals/NNNN-scope-based-submodules.md" class="">https://github.com/anandabits/swift-evolution/blob/scope-based-submodules/proposals/NNNN-scope-based-submodules.md</a></div><div class=""><br class=""></div><div class="">I am very much looking forward to everyone's feedback!</div><div class=""><br class=""></div><div class="">Matthew</div><div class=""><h1 id="scope-basedsubmodules" style="font-size: 37px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Scope-based submodules</h1><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Proposal: <a href="file:///Users/Matthew/Dropbox/Matthew/Development/__notes/__swift/evolution/NNNN-scope-based-submodules.md" style="color: rgb(13, 110, 161); text-decoration: none; transition: color 0.2s ease-in-out; -webkit-transition: color 0.2s ease-in-out;" class="">SE-NNNN</a></li><li style="font-size: 16.5px;" class="">Authors: <a href="https://github.com/anandabits" style="color: rgb(13, 110, 161); text-decoration: none; transition: color 0.2s ease-in-out; -webkit-transition: color 0.2s ease-in-out;" class="">Matthew Johnson</a></li><li style="font-size: 16.5px;" class="">Review Manager: TBD</li><li style="font-size: 16.5px;" class="">Status: <strong style="line-height: 1;" class="">Awaiting review</strong></li></ul><h2 id="introduction" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Introduction</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This proposal describes a submodule system based on the principle of strictly nested scopes. The design strives to follow the Swift philosophy of offering good defaults while progressively disclosing very powerful tools that can be used by experts to solve complex problems.</p><h2 id="motivation" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Motivation</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Swift currently provides two kinds of entities that provide system boundaries without directly introducing a symbol: modules and files*.</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Modules introduce an ABI boundary, a name boundary, and a scope boundary.</li><li style="font-size: 16.5px;" class="">Files introduce a scope boundary that carries no additional semantics.</li></ul><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Swift currently lacks the ability to introduce a name and scope boundary without also introducing an ABI boundary. Such a boundary would be naturally situated halfway between in terms of strength and ceremony. The lack of such a boundary significantly limits our abiltiy to structure a large Swift program. Introducing a way to form this kind of boundary will provide a powerful tool for giving internal structure to a module.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">*The important aspect of a file in Swift is the logical scope boundary it introduces. The physical file system representation is incidental to this. The appendix on file system independence discusses this in more detail.</p><h2 id="goals" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Goals</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Any discussion of submodules inevitably reveals that there are very different perspectives of what a submodule is, what problems submodules should be able to solve, etc. This section describes the design goals of this proposal in order to facilitate evaluation of both the goals themselves as well as how well the solution accomplishes those goals.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The primary goal of this proposal are to introduce a unit of encapsulation within a module that is larger than a file as a means of adding explicit structure to a large program. All other goals are subordinate to this goal and should be considered in light of it. </p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Some other goals of this proposal are:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Submodules should help us to manage and understand the internal dependencies of a large, complex system.</li><li style="font-size: 16.5px;" class="">Submodules should be able to collaborate with peer submodules without necessarily being exposed to the rest of the module.</li><li style="font-size: 16.5px;" class="">A module should not be <em style="line-height: 1;" class="">required</em> to expose its internal submodule structure to users when symbols are exported.</li><li style="font-size: 16.5px;" class="">It should be possible to extract a submodule from existing code with minimal friction. The only difficulty should be breaking any circular dependencies.</li></ul><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Some additional non-functional requirements for the solution are:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Submodules should not negatively impact runtime performance. WMO should be able to see across submodule boundaries.</li><li style="font-size: 16.5px;" class="">Submodules should not negatively impact build performance. Ideally they will improve build performance by giving the compiler more high-level information about internal dependencies.</li></ul><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Deferred goal:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">It is not an immediate goal to support submodules in single-file scripts. The appendix discussing file system independence discusses some ideas that could be used to support single-file scripts in the future.</li></ul><h2 id="proposedsolution" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Proposed solution</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">There are several relatively orthogonal aspects to the design of a submodule system. A design must answer the following questions:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">How is code placed in a submodule?</li><li style="font-size: 16.5px;" class="">How are symbols in one submodule made available to another submodule or module?</li><li style="font-size: 16.5px;" class="">How do submodules interact with access control?</li></ul><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This proposal diverages a little bit from the usual proposal format to faciliate discussion of alternatives within the context of each aspect of the chosen design. In each case an alternative could be substituted without compromising the overall design.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class=""><strong style="line-height: 1;" class="">Note:</strong> This proposal uses the term “top-level submodule” to distinguish the scope of code that is not explicitly placed in a submodule from the module as a whole. The top-level submodule is in most respects identical to any other parent submodule. There are two differences: 1) it is the only submodule that can export symbols outside of the module and 2) any <code style="line-height: 1;" class="">open</code> or <code style="line-height: 1;" class="">public</code> symbols it declares are automatically exported according to their access modifier.</p><h3 id="placingcodeinasubmodule" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Placing code in a submodule</h3><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Each file is part of the top level submodule by default.</p><h5 id="asubmoduledeclarationmaybeusedatthetopofafile" data-orig-id="asubmoduledeclarationmaybeusedatthetopofafile:" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">A <code style="line-height: 1;" class="">submodule</code> declaration may be used at the top of a file:</h5><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Only the first non-comment, non-whitespace line may contain a submodule declaration.</li><li style="font-size: 16.5px;" class="">The submodule decalaration looks like this: <code style="line-height: 1;" class="">submodule MySubmoduleName</code></li><li style="font-size: 16.5px;" class="">A submodule declaration may not be prefixed with the module name.</li></ul><h5 id="submodulenamesformahierarchicalpath" data-orig-id="submodulenamesformahierarchicalpath:" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Submodule names form a hierarchical path:</h5><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">The fully qualified name of the submodule specified by <code style="line-height: 1;" class="">Submodule.InnerSubmodule</code> is: <code style="line-height: 1;" class="">MyModuleName.Submodule.InnerSubmodule</code>.</li><li style="font-size: 16.5px;" class="">In this example, <code style="line-height: 1;" class="">InnerSubmodule</code> is a child of <code style="line-height: 1;" class="">Submodule</code>.</li><li style="font-size: 16.5px;" class="">A submodule may not have the same name as any of its ancestors. This follows the rule used by types.</li></ul><h5 id="submodulesmaynotbeextendedtheyformstrictlynestedscopes" data-orig-id="submodulesmaynotbeextended.theyformstrictlynestedscopes." style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Submodules may not be extended. They form strictly nested scopes.</h5><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">The <em style="line-height: 1;" class="">only</em> way to place code in a submodule is with a <code style="line-height: 1;" class="">submodule</code> declaration at the top of a file.</li><li style="font-size: 16.5px;" class="">All code in a file exists in a single submodule.</li></ul><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">A module is made up of strictly nested scoped that look like this:</p><figure style="display: inline-block; overflow: hidden; position: relative; margin: 1em 0px 2em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><img alt="The hierarchy of nested scopes in scope-based submodules" title="The hierarchy of nested scopes in scope-based submodules" style="max-width: 100%;" apple-inline="yes" id="1362C281-5572-43FE-9923-6F76C5ADFA6B" height="573" width="606" apple-width="yes" apple-height="yes" src="cid:7485F5F5-4A10-4A94-9E3C-0A6A30181825@Home" class=""><ins id="firstdiff" style="display: inline-block; position: absolute; left: -8px; text-decoration: none !important; border: none !important; background-image: none !important; background-position: initial initial !important; background-repeat: initial initial !important;" class=""></ins><figcaption style="font-style: italic; text-align: center; background-color: white; color: rgb(102, 102, 102); background-position: initial initial; background-repeat: initial initial;" class="">The hierarchy of nested scopes in scope-based submodules</figcaption></figure><span style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px; background-color: rgb(255, 255, 255);" class=""></span><h4 id="alternatives" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Alternatives</h4><h5 id="groupingmechanisms" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Grouping mechanisms</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">There are several other ways to specify which submodule the top-level scope of a file is in. All of these alternatives share a crucial problem: you can’t tell what submodule your code is in by looking at the file. </p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The alternatives are:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Use a manifest file. This would be painful to maintain.</li><li style="font-size: 16.5px;" class="">Use file system paths. This is too tightly coupled to physical organization. Appendix A discusses file system independence in more detail.</li><li style="font-size: 16.5px;" class="">Leave this up to the build system. This makes it more difficult for a module to support multiple build systems.</li></ul><h5 id="requireallfilestoincludeasubmoduledeclaration" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Require all files to include a <code style="line-height: 1;" class="">submodule</code> declaration</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">We could require all files to include an explicit submodule declaration. However, that would be a breaking change and would violate the principle of progressive disclosure. Users should not need to know about submodules if they don’t use them.</p><h5 id="allowsubmodulereferencestoexplicitlystatethenameofthemodule" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Allow submodule references to explicitly state the name of the module</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The module name is implicit throughout the scope of the entire module. Specifying it explicitly is redundant. Prohibiting explicit mention of the module name offers more flexibility for combining submodules into build products.</p><h3 id="visibilityofsubmodules" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Visibility of submodules</h3><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The <code style="line-height: 1;" class="">export</code> statement is used to modifiy the visibiltiy of a submodule within the module. It is also used by the top-level module to publish submodules to clients of the module.</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">All submodules are implicitly exported with module-wide visibility by default (and hidden outside of the module by default*).</li><li style="font-size: 16.5px;" class="">All submodules are implicitly <em style="line-height: 1;" class="">available</em> for export outside the module.</li><li style="font-size: 16.5px;" class="">A submodule may use an explicit <code style="line-height: 1;" class="">export</code> statement to <em style="line-height: 1;" class="">modify</em> the visibility of a descendent submodule.</li><li style="font-size: 16.5px;" class=""><code style="line-height: 1;" class="">export</code> statements are only allowed at the top level of a file.</li></ul><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">*The exception to this is that <code style="line-height: 1;" class="">open</code> and <code style="line-height: 1;" class="">public</code> symbols in the top-level submodule are always exported exactly as declared.</p><h4 id="top-levelexport" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Top-level export</h4><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">All export statements consist of an access modifier, the <code style="line-height: 1;" class="">export</code> keyword, and a submodule name:</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class=""><code style="line-height: 1;" class="">open export ChildSubmodule</code></p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">When this export statement appears in the top-level submodule, <code style="line-height: 1;" class="">ChildSubmodule</code> becomes available for import by clients of the submodule with the fully qualified name <code style="line-height: 1;" class="">Module.ChildSubmodule</code>. <code style="line-height: 1;" class="">public</code> exports are also available. When <code style="line-height: 1;" class="">public</code> is used all published symbols in the exported submodule have a maximum visiblity of <code style="line-height: 1;" class="">public</code>regardless of how they were declared.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Top-level <code style="line-height: 1;" class="">public</code> and <code style="line-height: 1;" class="">open</code> export statement may be modified with the following options:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">A submodule may be published under a different external name using the <code style="line-height: 1;" class="">export as NewName</code> syntax*.</li><li style="font-size: 16.5px;" class=""><code style="line-height: 1;" class="">@implicit</code> causes symbols from the submodule to be implicitly imported when the module is imported.</li><li style="font-size: 16.5px;" class=""><code style="line-height: 1;" class="">@inline</code> causes the symbols from the submodule to appear as if they had been declared directly within the top-level submodule.</li><li style="font-size: 16.5px;" class=""><code style="line-height: 1;" class="">@implicit</code> may be combined with renaming but <code style="line-height: 1;" class="">@inline</code> may not appear along with either of them.</li></ul><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">*When a submodule is renamed for export with the <code style="line-height: 1;" class="">as</code> clause its internal name does not change. A submodule always has the same fully qualfied name everywhere within its module.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Here are some example export statements:</p><pre style="margin-top: 21px; margin-bottom: 21px; tab-size: 4; color: rgb(17, 17, 17); font-size: 15px; background-color: rgb(248, 248, 248); height: 729px;" class=""><code class="swift hljs" style="line-height: inherit; display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); height: auto;"><span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// All symbols in `Child1` are available for import by clients as `Module.Foo`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// These symbols are *not* imported automatically when a client imports the module with `import Module`</span>
<span class="hljs-keyword" style="font-weight: bold;">public</span> export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child1</span> <span class="hljs-keyword" style="font-weight: bold;">as</span> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Foo</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// All symbols in `Child2` are available for explicit import by clients as `Module.Child2`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// The symbols are also automatically imported when a client imports the module with `import Module`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// When the symbols are imported implicitly they retain the fully qualified name prefix of `Module.Child2`</span>
@implicit open export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child2</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// All symbols in `Child3` are available for explicit import by clients as `Module.Foo.Bar`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// The symbols are also automatically imported when a client imports the module with `import Module`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// When the symbols are imported implicitly they retain the fully qualified name prefix of `Module.Foo.Bar`</span>
@implicit open export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child3</span> <span class="hljs-keyword" style="font-weight: bold;">as</span> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Foo</span>.<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Bar</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// All symbols in `Child4.Grandchild` appear to clients as if they had been declared</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// directly in the top-level submodule.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// If the process of inlining the symbols produces duplicate symbols a compiler error is produced</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// at the site of one or both of the `export` statements.</span>
@inline <span class="hljs-keyword" style="font-weight: bold;">public</span> export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child4</span>.<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Grandchild</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// All symbols in `Child5.Grandchild` are available for explicit import by clients as `Module.Foo` </span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// along with the symbols declared in `Child`.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// The symbols are also automatically imported when a client imports the module with `import Module`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// When the symbols are imported implicitly they retain the fully qualified name prefix of `Module.Foo`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// As with `@inline`, when two submodules are given the same external name a duplicate symbol error may occur.</span>
@implicit <span class="hljs-keyword" style="font-weight: bold;">public</span> export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child5</span>.<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Grandchild</span> <span class="hljs-keyword" style="font-weight: bold;">as</span> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Foo</span></code></pre><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">One interesting observation is that both <code style="line-height: 1;" class="">Child1</code> and <code style="line-height: 1;" class="">Child5.Grandchild</code> are renamed to <code style="line-height: 1;" class="">Foo</code>. The symbols declared former is not implicitly imported by <code style="line-height: 1;" class="">import Module</code> but the latter is, despite having the same fully qualified name prefix.</p><h4 id="exportswithinthemodule" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Exports within the module</h4><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">A submodule may bound the maximum visibility of any of its descendent submodules by explicitly exporting it:</p><pre style="margin-top: 21px; margin-bottom: 21px; tab-size: 4; color: rgb(17, 17, 17); font-size: 15px; background-color: rgb(248, 248, 248); height: 267px;" class=""><code class="swift hljs" style="line-height: inherit; display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); height: auto;"><span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// `Child1.Grandchild` may be exported by the top-level module, but only with `public` visibility.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// `Child1.Grandchild` may not be exported as `open`.</span>
<span class="hljs-keyword" style="font-weight: bold;">public</span> export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child1</span>.<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Grandchild</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// `Child2` is exported with `internal` visibility.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// Because `internal` is scoped to the submodule level *only* the parent submodule can see `Child2`.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// No submodules except the direct parent of `Child2` (the current submodule) are allowed to `import Child2`.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// This also implies that the `Child2` may not be exported to clients because the top-level </span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// submodule is not able to see or reference `Child2` at all.</span>
<span class="hljs-keyword" style="font-weight: bold;">internal</span> export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child2</span></code></pre><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">The access modifier may specify a scope <code style="line-height: 1;" class="">internal</code> or greater.</li><li style="font-size: 16.5px;" class="">Only the <strong style="line-height: 1;" class="">direct</strong> parent of a submodule may specify the <code style="line-height: 1;" class="">internal</code> modifier. A grandparent cannot hide a grandchild from its parent.</li><li style="font-size: 16.5px;" class="">If a descendent includes an <code style="line-height: 1;" class="">export</code> statement for the same submodule, the access modifier must be <strong style="line-height: 1;" class="">no greater than</strong> the access modifier specified by the descendent. An ancestor may provide a tighter bound to visibility but may not increase visibility. An attempt to increase visibility results in an error.</li></ul><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class=""><strong style="line-height: 1;" class="">Note:</strong> If a submodule is not visible none of its descendents is visible either.</p><h4 id="alternatives2" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Alternatives</h4><h5 id="useimportaccessmodifierstoexportasubmodule" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Use <code style="line-height: 1;" class="">import</code> access modifiers to export a submodule</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The semantics of placing a bound on the visibility of a descendent submodule is significantly different than the semantics of importing symbols from a submodule into the current lexical scope. Mixing the semantics of the two is confusing.</p><h5 id="restrictthevisibilityofasubmoduletoitsparentunlesstheparentexplicitlyexportsit" data-orig-id="restrictthevisibilityofasubmoduletoitsparentunlesstheparentexplicitlyexportsit." style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Restrict the visibility of a submodule to its parent unless the parent explicitly exports it.</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Users should be able to use submodules without needing to place <code style="line-height: 1;" class="">export</code> statements in every parent submodule. Module-wide default visibility for submodules is analagous to <code style="line-height: 1;" class="">internal</code> default visibility for symbols.</p><h5 id="requireallsubmodulestobevisiblemodule-wide" data-orig-id="requireallsubmodulestobevisiblemodule-wide." style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Require all submodules to be visible module-wide.</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This removes an important tool for bounded collaboration within a complex system. A parent submodule should be allowed to have a child submodule(s) which are implementation details of the parent and not exposed to the rest of the module.</p><h5 id="allowrenamingtobeusedbyexportstatementswithinthemodule" data-orig-id="allowrenamingtobeusedbyexportstatementswithinthemodule." style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Allow renaming to be used by export statements within the module.</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">A submodule should have the same fully qualified name everywhere it is used within a single module, whether that be the declaring module or a client module. The declaring module and client modules may see different names, but each sees a name that is consistent fully qualified name everywhere the submodule is referenced.</p><h5 id="allowinlinetobeusedbyexportstatementswithinthemodule" data-orig-id="allowinlinetobeusedbyexportstatementswithinthemodule." style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Allow <code style="line-height: 1;" class="">@inline</code> to be used by export statements within the module.</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">As with renaming, a symbol should have a single fully qualified name everywhere within a single module.</p><h5 id="allowimplicittobeusedbyexportstatementswithinthemodule" data-orig-id="allowimplicittobeusedbyexportstatementswithinthemodule." style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Allow <code style="line-height: 1;" class="">@implicit</code> to be used by export statements within the module.</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This would reduce the visibility of internal dependencies. If we find that import-per-submodule becomes boilerplate-y this is an easy feature to add later.</p><h3 id="importingsubmodules" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Importing submodules</h3><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Submodules are imported in exactly the same way as an external module by using an <code style="line-height: 1;" class="">import</code> statement. There are a few additional details that are not applicable for external modules:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Circular imports are not allowed.</li><li style="font-size: 16.5px;" class="">A submodule may not import any of its ancestors.</li><li style="font-size: 16.5px;" class="">Relative child and sibling names are allowed using the same rules that apply to nested types.</li></ul><h3 id="accesscontrol" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Access control</h3><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">An access modifier applies an upper bound to the scope in which a symbol or submodule is visible. With the introduction of submodules, <code style="line-height: 1;" class="">internal</code> now applies at the level of a submodule: only the current submodule may see an <code style="line-height: 1;" class="">internal</code> entity. We need a new way to specify module-wide visibility.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This proposal builds on Option 2 in the proposal Fix Private Access Levels which reverts <code style="line-height: 1;" class="">private</code> to the Swift 2 meaning (equivalent to <code style="line-height: 1;" class="">fileprivate</code>) and uses <code style="line-height: 1;" class="">scoped</code> for the Swift 3 scoped access feature. It does this by allowing the <code style="line-height: 1;" class="">scoped</code> access modifier to be parameterized with a scope reference. By <strong style="line-height: 1;" class="">defaults</strong> it references the scope in which it appears, but any ancestor scope may be specified as a parameter.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The paremeterization of the <code style="line-height: 1;" class="">scoped</code> access modifier provides a simple yet powerful way for a submodule to bound the visibility of a descendent.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Some examples of using <code style="line-height: 1;" class="">scoped</code> exports are:</p><pre style="margin-top: 21px; margin-bottom: 21px; tab-size: 4; color: rgb(17, 17, 17); font-size: 15px; background-color: rgb(248, 248, 248); height: 225px;" class=""><code class="swift hljs" style="line-height: inherit; display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); height: auto;">submodule <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Parent</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// `Grandparent` and all of its descendents can see `Child1` (fully qualified: `Grandparent.Parent.Child1`)</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// This reads: `Child1` is scoped to `Grandparent`.</span>
scoped(<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Grandparent</span>) export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child1</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// `Child2` is visible throughout the module but may not be exported for use by clients.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// This reads: `Child2` is scoped to the module.</span>
scoped(module) export <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Child2</span></code></pre><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">With parameterization, <code style="line-height: 1;" class="">scoped</code> has the power to specify <strong style="line-height: 1;" class="">all</strong> access levels that Swift has today:</p><pre style="margin-top: 21px; margin-bottom: 21px; tab-size: 4; color: rgb(17, 17, 17); font-size: 15px; background-color: rgb(248, 248, 248); height: 141px;" class=""><code class="(null) clean hljs" style="line-height: inherit; display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); height: auto;">`scoped` == `private` (Swift <span class="hljs-number" style="color: rgb(0, 128, 128);">3</span>)
`scoped(file)` == `private` (Swift <span class="hljs-number" style="color: rgb(0, 128, 128);">2</span> & <span class="hljs-number" style="color: rgb(0, 128, 128);">4</span>?) == `fileprivate` (Swift <span class="hljs-number" style="color: rgb(0, 128, 128);">3</span>)
`scoped(submodule)` == `internal`
`scoped(public) scoped(internal, inherit)`* == `public`
`scoped(public)` == `open`</code></pre><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This design is a direct generalization of the principle underlying Swift’s existing access control system. It unifies the semantics of the system under the single elegant mechanism of ancestor scope references. </p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">While it is <em style="line-height: 1;" class="">possible</em> to specify all access levels using <code style="line-height: 1;" class="">scoped</code> that is not recommended. The aliases <code style="line-height: 1;" class="">public</code>, <code style="line-height: 1;" class="">private</code>(Swift 2) and <code style="line-height: 1;" class="">internal</code> provide excellent default access levels that don’t require a user to think about scope hierarchies. Using the default access levels when possible calls extra attention to cases where a different choice was made.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">*This is a conceptual model. This proposal does not introduce the <code style="line-height: 1;" class="">inherit</code> or <code style="line-height: 1;" class="">override</code> parameter to access modifiers. It could be added in the future as a way to bound inheritance within a module. It would work similarly to <code style="line-height: 1;" class="">private(set)</code> does in Swift today.</p><h5 id="aside" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Aside</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The parameterization of <code style="line-height: 1;" class="">scoped</code> also allows us to reference other scopes that we cannot in today’s system, specifically extensions: <code style="line-height: 1;" class="">scoped(extension)</code> and outer types: <code style="line-height: 1;" class="">scoped(TypeName)</code>.</p><h4 id="alternatives3" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Alternatives</h4><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">If we don’t adopt the approach of parameterizing <code style="line-height: 1;" class="">scoped</code> our options for access control include:</p><h5 id="submodulesareonlyallowedtoseepublicandopensymbolsfromothersubmodules" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Submodules are only allowed to see <code style="line-height: 1;" class="">public</code> and <code style="line-height: 1;" class="">open</code> symbols from other submodules</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">A module-wide scope is highly desirable. People might avoid using submodules if this is not available.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This approach also creates a lot more friction when refactoring. A possible workaround to the lack of a module-wide scope in this system is to place code in a non-exported submodule and declare symbols <code style="line-height: 1;" class="">public</code>. Even with the workaround, extracting a submodule may not always be possible or desirable and the <code style="line-height: 1;" class="">public</code> access modifiers required would be misleading. It would be much better to be able to state our intent directly.</p><h5 id="useinternaltocoverthewholemoduleandprivatetocoverasubmodule" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Use <code style="line-height: 1;" class="">internal to cover the whole module and</code> <code style="line-height: 1;" class="">private</code> to cover a submodule</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">One suggestion that has appeared is the idea of removing <code style="line-height: 1;" class="">fileprivate</code> and making <code style="line-height: 1;" class="">private</code> be submodule-wide. <code style="line-height: 1;" class="">internal</code> would remain module-wide. This is too coarse - <em style="line-height: 1;" class="">many</em> people want a file-level scope.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class=""><code style="line-height: 1;" class="">internal</code> is Swift’s default access modifier. A symbol with default access modifier should not be able to cross a submodule boundary implicitly.</p><h5 id="addthemoduleinternalaccessmodifier" style="color: rgb(17, 17, 17); font-size: 1.1429em; line-height: 1.3125em; margin: 1.3125em 0px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Add the <code style="line-height: 1;" class="">moduleinternal</code> access modifier</h5><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This is about as ugly as <code style="line-height: 1;" class="">fileprivate</code>.</p><h2 id="detaileddesign" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Detailed design</h2><h3 id="exporterrors" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Export errors</h3><h4 id="multipleexportsofthesamesubmodule" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Multiple exports of the same submodule</h4><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">If a submodule exports the same descendent more than once and the semantics of the declarations are not identical an error is produced.</p><h4 id="symbolflattening" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Symbol flattening</h4><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">When a submodule is exported by the top-level module using the <code style="line-height: 1;" class="">@inline</code> attribute it is possible that there will be conflicting symbol definitions in the child and the top-level submodule (or other inlined submodules). This results in a compiler error at the site of the conflicing <code style="line-height: 1;" class="">@inline export</code> statements.</p><h4 id="overlappingrenames" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Overlapping renames</h4><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">As with flattening, when two or more submodules are given the same external name symbol conflicts are possible. This also results in a compiler error at the site of the conflicting <code style="line-height: 1;" class="">export as</code> statements.</p><h4 id="accesserrorsduringexportifthespecifiedaccessmodifierexceedsmaximum" style="color: rgb(17, 17, 17); font-size: 20px; line-height: 21px; margin-top: 21px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Access errors during export if the specified access modifier exceeds maximum</h4><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">An error is produced when an export statement includes an access modifier greater than the bound provided for the exported submodule by a descendent of the exporting submodule.</p><h2 id="sourcecompatibility" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Source compatibility</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This proposal is purely additive. That said, it would be a breaking change for the standard library to move existing API into an externally visible submodule.</p><h2 id="effectonabistability" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Effect on ABI stability</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This proposal is purely additive. That said, it would be a breaking change for the standard library to move existing API into an externally visible submodule.</p><h2 id="effectonapiresilience" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Effect on API resilience</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">This proposal is purely additive.</p><h2 id="futuredirections" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Future directions</h2><h3 id="selectiveexportandimport" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Selective export and import</h3><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The ability to import and export individual symbols would be a very nice to have.</p><h3 id="scopedimport" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Scoped import</h3><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The ability to import modules, submodules, and symbols into any lexical scope would be nice to have.</p><h3 id="boundedinheritance" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Bounded inheritance</h3><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">It could be useful to have the ability to bound inheritance within a module. This could be accomplished by inroducing <code style="line-height: 1;" class="">inherit</code> and <code style="line-height: 1;" class="">override</code> parameters for access modifiers (which would work similarly to the existing <code style="line-height: 1;" class="">set</code> parameter).</p><h2 id="appendixafilesystemindependence" data-orig-id="appendixa:filesystemindependence" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Appendix A: file system independence</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The submodule design specified by this proposal is file system independent. The only relationship it has with the physical file system is that a file introduces an anonymous scope boundary which is referenced by <code style="line-height: 1;" class="">scoped(file)</code> or <code style="line-height: 1;" class="">fileprivate</code> (Swift 3) or <code style="line-height: 1;" class="">private</code> (Swift 2 and 4?).</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The logical role of a “file” in this design is to provide a boundary of encapsulation that is even lighter weight than a submodule: it doesn’t hide names. All declarations are implicitly available not only <em style="line-height: 1;" class="">within</em> the file but also <em style="line-height: 1;" class="">across</em> the file boundary (modulo access control). Files are to submodules as submodules are to modules.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">If a future version of Swift were to eliminate files in favor of some kind of code browser it would still be very useful to have the ability to form a pure scope boundary (with no additional semantics). A <code style="line-height: 1;" class="">scope</code> declaration could be used to do this. Scope declarations could have an optional (or required) name and could even be nested. In this system <code style="line-height: 1;" class="">private</code>would reference the nearest anonymous ancestor scope declaration (or would be removed if we don’t allow anonymous scopes).</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The logical structure of this design can be directly translated into a grammar that could be represented directly with syntax. Such a grammer could be used to support scripts with submodules. An example follows:</p><pre style="margin-top: 21px; margin-bottom: 21px; tab-size: 4; color: rgb(17, 17, 17); font-size: 15px; background-color: rgb(248, 248, 248); height: 960px;" class=""><code class="(null) dts hljs" style="line-height: inherit; display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); height: auto;"><span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// A module contans a single implicit, anonymous submodule.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// submodule {</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// A submodule may contain `scope` declarations (i.e. files) as well as other submodules.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// An anonymous scope is equivalent to a file in current Swift.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// If we introduce lexical scopes we would probably require them to be named explicitly.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// This example uses the anonymous scope in order to most closely match the role files play in the current system.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// Because `scope` does not provide a name boundary all names declared in one scope</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// are visible in other scopes (modulo access control)</span>
<span class="hljs-class">scope </span>{
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// Top-level declarations go here.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// This is equivalent to the top level of a file in Swift today.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// It is also equivalent to the top level of a file that does not contain </span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// a `submodule` declaration in this proposal.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// It would be possible to allow nested, named scopes.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// A scope name participates in the scope and name hierachies.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// However, it does not form a name boundary like a submodule does.</span>
scope <span class="hljs-class">Named </span>{
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// This declares the static variable `Named.foo`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// `scoped(file)` references the nearest anonymous ancestor scope.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// It is used in this example for specificity.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// Real code would use the alias `private` or `fileprivate`</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// If we introduce explicit scope syntax we would probably want a better name to refer</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// to the nearest anonymous scope than `file` or we may just require all scopes to have a name.</span>
scoped(file) var foo: String
}
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// `Named.foo` is visible here</span>
}
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// `Named.foo` is not visible here.</span>
submodule <span class="hljs-class">Foo </span>{}
submodule <span class="hljs-class">Baz </span>{}
submodule <span class="hljs-class">Buzz </span>{
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// Equivalient to a file in current Swift.</span>
<span class="hljs-class">scope </span>{
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// submodule declarations go here.</span>
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// This is equivalent to the top level scope of a file that contains the `submodule Foo` declaration.</span>
}
<span class="hljs-class">scope </span>{}
submodule <span class="hljs-class">Baz </span>{}
}
<span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">//}</span></code></pre><h2 id="appendixbnamespacestylesubmodules" data-orig-id="appendixb:namespacestylesubmodules" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">Appendix B: namespace style submodules</h2><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">It is possible to design a system that allows a name boundary to be formed without also forming a scope boundary. A natural consequence of this is that symbols may be placed into a namespace-style submodule in many (unlimited) scopes via extension (even extension outside the module is theoretically possible). Allowing this runs contray to both of the two primary goals of this proposal (encapsulation and structure).</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Allowing a submodule to be extended in multiple scopes precludes the possibility of submodule internal visibility. A submodule internal access modifier could still be defined but it would not provide the guarantee it purports to. The submodule can be opened by extension anywhere within the module. If a lazy developer wants to access a submodule internal symbol from a distant subsytem all they need to do is add an extension and wrap the submodule internal symbol with a new symbol offering higher visibility*. In such a system there is the same wide gap between file scope and module scope that exists today.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Allowing a submodule to be extended in multiple scopes precludes the ability to introduce real structure to a module. We are able to introduce structure to the <em style="line-height: 1;" class="">names</em> but not the module itself. The structure of a submodule in such a system may be widely dispersed throughout the module. It is not part of a strictly hierarchical structure of scopes which each having a single designated location within the larger structure.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">What you <em style="line-height: 1;" class="">do</em> get from name boundaries that do not also form a scope boundary is a soft form of symbol hiding (soft because <em style="line-height: 1;" class="">all</em> submodules are available for import or extension anywhere within the program). This does provide some value, but not nearly as much value as is provided by a name boundary that is accompanied by a scope boundary.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Another downside to namespace-style submodules that are open to extension is that they are much less likely to facilitate improved build performance because they don’t add any physical structure to the system.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Finally, lexical submodules have the potential to be confusing. If submodules form a name boundary (even a soft one) an import statement is required to access the symbols declared inside a submodule. Is code that surrounds a lexical submodule declaration able to see the symbols it declares without importing them? Most developers will expect the symbols to be available. It is probably necessary to make an exception to name boundary for the surrounding lexical context. However, if an exception is made then this system relies heavily on a file to provide a bound to the implicit symbol import.</p><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">*It is worth observing that the ability to violate encapsulation via extension (or subclassing) is one of the primary reasons Swift does not offer type-based access modifiers such as <code style="line-height: 1;" class="">typeprivate</code> or <code style="line-height: 1;" class="">protected</code>. The do not offer true encapsulation at all. They are a statement of intent that cannot really be verified in the way that is desired. They form a permeable rather than a hard boundary.</p></div></body></html>