[swift-evolution] [Pitch] Let's talk about submodules

Rien Rien at Balancingrock.nl
Tue Feb 21 01:20:33 CST 2017


Maybe we should try to collect what people want from submodules first.

I wanted modules for organisational purposes, however with the arrival of SPM that need has been almost completely removed. At least to the point that I do not feel that they are absolutely necessary.

Have the people who want modules tried SPM yet?

PS: be prepared for additional access levels requests when modules are available… :-0

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl





> On 21 Feb 2017, at 02:36, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
> 
> Okay, lots of people want to have some kind of submodule feature, so I'd like to sketch one out so we can hopefully agree on what submodules might look like.
> 
> ***
> 
> Any group of Swift files can be grouped together to form a submodule. Submodules belong within a particular module, and have a dotted name: If `ModKit` is a module, it might have a submodule called `ModKit.Foo`. Submodules can be nested within one another: `ModKit.Foo.Bar` is a submodule of `ModKit.Foo`, which is a submodule of `ModKit`.
> 
> No new access levels are necessary. `internal` APIs are only visible within the submodule they're declared in; a module cannot see its submodules' `internal` APIs, and a submodule cannot see its parent module's `internal` APIs. If a submodule wants to expose some of its APIs to its parent or sibling modules, it must mark them as `public` or `open`. Then they can import the submodule to see its APIs:
> 
> 	import ModKit.Foo
> 
> By default, outside modules cannot import a submodule. But an import in the parent module can be decorated by an access control keyword to allow that:
> 
> 	/// Any module outside ModKit can import ModKit.Foo and access its `public` and `open` APIs.
> 	open import ModKit.Foo
> 
> 	/// Any module outside ModKit can import ModKit.Foo and access its `public` and `open` APIs, 
> 	/// except `open` APIs are treated as `public`.
> 	public import ModKit.Foo
> 
> Imports may also be decorated by the `@exported` attribute, which exposes the submodule's APIs as though they were parent module APIs:
> 
> 	@exported open import ModKit.Foo
> 
> 	@exported public import ModKit.Foo
> 
> (This is sort of half-implemented already in a buggy `@_exported` attribute.)
> 
> Finally, the standard syntax for importing individual symbols can be used to cherry-pick types to treat differently:
> 
> 	// Most ModKit.Foo APIs are not importable...
> 	import ModKit.Foo
> 
> 	// ...but SomeEnum can be imported as public...
> 	public import enum ModKit.Foo.SomeEnum
> 
> 	// ...SomeClass can be imported as open...
> 	open import class ModKit.Foo.SomeClass
> 
> 	// And ImportantStruct will import whenever you import ModKit.
> 	@exported public import struct ModKit.Foo.ImportantStruct
> 
> (This syntax should be enhanced to allow cherry-picked importing of global functions, constants, and variables.)
> 
> If there are several different `import`s covering the same submodule or submodule symbol, the most permissive one wins.
> 
> (In large projects, `public`, `open`, and `@exported` imports will most likely all be put in a single Policy.swift file or something, but this is not enforced by the language.)
> 
> A submodule may not import any direct parent module (parent, grandparent, etc.), but may import any other submodule in the same module. This list shows permitted imports for a project with four modules/submodules:
> 
> 	ModKit
> 		- ModKit.Foo
> 		- ModKit.Foo.Bar
> 		- ModKit.Quux
> 	ModKit.Foo
> 		- ModKit.Foo.Bar
> 		- ModKit.Quux
> 	ModKit.Foo.Bar
> 		- ModKit.Quux
> 	ModKit.Quux
> 		- ModKit.Foo
> 		- ModKit.Foo.Bar
> 
> However, submodules may not form circular dependencies through imports—if `ModKit.Quux` imports `ModKit.Foo`, then `ModKit.Foo` cannot import `ModKit.Quux`. The `#if canImport()` feature cannot be used to probe for other submodules within the same top-level module you're in.
> 
> At the compiler driver level, a submodule is specified by giving a `-module-name` parameter with a dot in it. When a file is compiled, only the filenames of the other .swift files in the same module are specified, along with .o files for any submodules; then all the .o files within that submodule are linked into a single .o file for the whole submodule. So files in `ModKit.Foo` would be compiled with only the .swift files in `ModKit.Foo` and the .o file for `ModKit.Foo.Bar`; then all the `ModKit.Foo` .o files would be linked into one .o file for the top-level `ModKit` to use. None of `ModKit.Foo`'s .swift files would be included in the command line when compiling the top-level `ModKit` module.
> 
> (That bit is kind of speculative—particularly the idea of linking submodule files into a single .o file—but I think something like what I'm describing could work.)
> 
> Because the compiler driver is used to group submodules together, Xcode can specify submodules in project file metadata and calculate a submodule dependency graph, while SwiftPM can use folders and compile submodules whenever the compiler emits an error indicating that a file tried to import a nonexistent submodule. Other build systems can do whatever best suits their style.
> 
> ***
> 
> Thoughts?
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list