> On Feb 20, 2017, at 11:39 PM, Matthew Johnson <[email protected]> wrote:
>
> Thanks for bringing up submodules Robert. I agree it's a good time to
> discuss them.
>
> There seem to be two broad approaches to submodules. One is more of a
> physical / encapsulation based view and the other is more of a logical /
> namespace based view. This proposal falls into the latter group (Brent's
> pitch falls into the former).
>
> Before I offer feedback on this proposal I'm wondering if you can provide
> some solid examples of what benefits you see in the ability of a single file
> to participate in more than one submodule.
A single file defining more than one submodule is like a single file defining
more than one data structure/extension. If you decide that particular
functionality deserves to reside in separate areas of concern, but don’t wish
to break it out into separate files for whatever reason, just don’t. Can you
be more specific about the kind of thing you’re looking for?
> And also, what problems do you foresee if a file were restricted to being in
> a single submodule (or at the top level of the module)?
The top level case is called out in the proposal. We felt that requiring a
top-level module declaration in every file to opt-in would be a needless
complication to the semantics and would introduce an identifier-addressing
problem. Specifically, because modules aren’t namespaces we don’t have a way
to refer to the “anonymous/global" top-level namespace as in C++ with a bare
::, so this would become ambiguous without additional syntax
// Explicit declaration of top-level module Foo
module Foo {
// Decls...
}
// Where does this constant live? How can I address it from within Foo?
// Why isn’t it just a part of Foo?
let string = “Hello World!”
For one-file-per-module, that kind of restriction represents a particular way
of organizing code and is a design pattern that is supported under this
proposal. We just happen to not enforce that particular pattern, and feel that
it is the job of a linter to do so. Really, this kind of restriction is to
ease the mental burden on compiler writers who use it to build compilation unit
dependency graphs. Swift already considers all files when building its modules
because you can extend any type (and now, any module) from any one of them so
it doesn’t buy us anything other than an arbitrary restriction.
More generally, we need to move access control away as far away from
filesystems as possible. One day, the compiler is going to get ported over to
a platform with some bonkers rules that are going to turn around and bite us.
~ Robert Widmann
>
> Sent from my iPad
>
> On Feb 20, 2017, at 7:56 PM, Robert Widmann via swift-evolution
> <[email protected] <mailto:[email protected]>> wrote:
>
>> Good Evening All,
>>
>> Jaden Geller and I have been considering a (sub)module system for Swift that
>> would complement the existing language but also provide sorely needed
>> modularity. A draft of the proposal is attached to this email, but it can
>> also be read as a gist
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a> if you
>> desire.
>>
>> Cheers,
>>
>> ~Robert Widmann
>>
>> Modular Swift
>>
>> Proposal: SE-NNNN <https://gist.github.com/CodaFi/NNNN-filename.md>
>> Authors: Robert Widmann <https://github.com/codafi>, Jaden Geller
>> <https://github.com/JadenGeller>
>> Review Manager: TBD
>> Status: Awaiting review
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#introduction>Introduction
>>
>> Almost every major programming language supports some form of modular
>> programming through constructs like (sub)modules, packages, or interfaces.
>> Swift, though it provides top-level modules to organize code under, does not
>> provide a complete implementation of any of these concepts, which has led
>> instead to the proliferation of access control levels. This has not proven
>> an effective way to decompose programs into manageable parts, and exposes
>> the need for a real system of modules to solve this modularity problem once
>> and for all.
>>
>> Separation of code into distinct islands of functionality should be a
>> first-class construct in the language, not dependent on external files and
>> tools or filesystems. To that end, we propose the introduction of a
>> lightweight module system for Swift.
>>
>> Swift-evolution thread <applewebdata://CC9A198B-9963-4B27-A62C-22EC5FD1B099>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#motivation>Motivation
>>
>> Swift has reached a point in its evolution where rich libraries and large
>> projects that take on many dependencies have matured significantly. To
>> accomodate the information-hiding and semantics-signalling needs of these
>> users at the time, Swift began its access control story with just three
>> access modifiers: public, private, and internal then grew fileprivate and
>> open as the need to express locality of implementation and "subclassability"
>> arose respectively. In doing so, Swift's access control scheme has become
>> anti-modular.
>>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#proposed-solution>Proposed
>> solution
>>
>> We propose the introduction of a lightweight module system for Swift. More
>> than simply namspaces, a module declaration interacts with Swift's access
>> control to provide an API boundary that allows better control over an
>> interface's design.
>>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#detailed-design>Detailed
>> design
>>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#syntax>Syntax
>>
>> A module is a named region that introduces a lexical scope into which
>> declarations may be nested. The name of the module can be used to access
>> these member declarations. A module, like other aggregate structures in
>> Swift, may be extended with new declarations over one or more translation
>> units (files).
>>
>> We propose a new declaration kind, module-decl be added to the language. A
>> proposed grammar using the new modulekeyword is given below:
>>
>> GRAMMAR OF A MODULE DECLARATION
>>
>> module-declaration -> `module` module-identifier module-body
>> module-name -> identifier
>> module-body -> { module-members(opt) }
>> module-members -> module-member module-members(opt)
>> module-member -> declaration | compiler-control-statement
>> GRAMMAR OF A DECLARATION
>>
>> + declaration -> module-declaration
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#general-semantics>General
>> Semantics
>>
>> Syntax and semantics for imports, as it already supports referencing
>> submodules imported from C and Objective-C modules, remains unchanged:
>>
>> // The outermost module is given explicitly
>> // by passing `-module-name=Foo` or exists implicitly, as today.
>> // module Foo {
>> public class A {}
>>
>> module Bar {
>> module Baz {
>> public class C {}
>> }
>>
>> public class B {}
>> }
>>
>> let message = "Hello, Wisconsin!"
>> // } // End declarations added to module Foo.
>> To consume this interface:
>>
>> // imports all of Foo, Foo.Bar, and Foo.Bar.Baz
>> import Foo.Bar.Baz
>>
>> // imports Foo.A as A
>> import class Foo.A
>> // imports Foo.Bar.B as B
>> import class Foo.Bar.B
>> // imports Foo.Bar.Baz.C as C
>> import class Foo.Bar.Baz.C
>> A module declaration may only appear as a top-level entity or as a member of
>> another module declaration. The following code is therefore invalid:
>>
>> module Foo {
>> class Bar {
>> module Baz {} // error: module declaration cannot be nested inside type
>> 'Bar'
>> }
>> }
>> To extend an existing module declaration, simply reference its module name
>> in an extension declaration.
>>
>> // In module 'Foo'
>> module Bar {
>> public class A {}
>>
>> module Baz {}
>> }
>>
>> extension Bar {
>> public struct B {}
>> }
>>
>> extension Bar.Baz {
>> public enum C { case D }
>> }
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#modules-and-access-control>Modules
>> and Access Control
>>
>> The semantics of some existing access control modifiers shall also be
>> extended to support module declarations:
>>
>> open and public declarations are exported by a module for consumption by
>> clients of the module.
>> internal declarations scope over the entire module and any derived
>> submodules.
>> By default, to preserve encapsulation of interfaces, modules are "sealed"
>> and may only be "opened" by explicit named import. However, it is often
>> desirable to export a module and a set of submodules or even modules from
>> external dependencies along with a given interface. We propose the public
>> keyword be used for this purpose:
>>
>> // Defines top-level module "Foo"
>> //module Foo {
>> public import Foo.Bar.Baz
>> public import Foundation.Date
>> //}
>> Which then causes the following (sub)modules to be imported into scope along
>> with Foo:
>>
>> // imports Foo, Foo.Bar.Baz, and Foundation.Date
>> import Foo
>> To support existing Swift packages that cannot have opted into modules, and
>> to preserve the scriptable nature of Swift, module declarations shall be
>> optional. Any Swift program that does not declare at least one top-level
>> module explicitly is considered part of an unnamed special "Global Module"
>> with the same rules of access control as today. To give declarations in the
>> Global Module an explicit module without using a module declaration, use the
>> -module-name flag.
>>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#impact-on-existing-code>Impact
>> on Existing Code
>>
>> This proposal is intentionally additive. There is no impact on existing code.
>>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#alternatives-considered>Alternatives
>> considered
>>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#explicit-modules-everywhere>Explicit
>> Modules Everywhere
>>
>> Declarations in the top-level of a program exist today in the top-level of
>> the corresponding module. If desired, this module declaration could be
>> required to be explicit like so:
>>
>> module Foo {
>> module Bar {
>> module Baz {}
>> }
>> }
>> However, we feel that imposing such a requirement not only complicates the
>> outermost scope, it requires inserting needless extension Foo {} scopes in
>> every file. It also violates the principle of progressive disclosure by
>> forcing all new adoptees of Swift to learn what a module is without actually
>> using the module system.
>>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#nested-extensions>Nested
>> Extensions
>>
>> Nested module extensions may be "expanded" as it were to the following:
>>
>> module Foo {
>> module Bar {}
>> }
>>
>> extension Foo {
>> extension Bar {}
>> }
>> However, this syntax is currently not enabled in general in Swift. This
>> problem should be revisted in a future proposal.
>>
>>
>> <https://gist.github.com/CodaFi/cd66b7d70b5cd8e4e8b433fa2ace378a#deprecations-source-breaking-changes>Deprecations
>> (Source-Breaking Changes)
>>
>> The system described above is intended to be entirely source and binary
>> compatible. Nonetheless, in its design we feel we have obviated certain
>> existing features and recommend their deprecation in future proposals:
>>
>> fileprivate access can be recreated by creating a private "utility
>> submodule" containing declarations of at least internal access.
>> @_exported, the private directive to re-export modules today, should be
>> deprecated and removed.
>>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution