Totally agree with Joe here. I’d like to see a simplified version of the import 
design through ASAP. Mot people will quickly agree with it. The rest of the 
proposal is much more up for discussion IMHO.

> On 19 Jul 2016, at 03:19, Joe Groff via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> Our import story definitely needs work, and this is a step in the right 
> direction. Thanks for working on this! Some comments:
> 
> - The import changes can be separated from the submodule issues. Enhancing 
> imports is IMO more important, and is source-breaking today, whereas 'module 
> ' declarations and submodules can be added later. I'd suggest breaking this 
> into two proposals.
> - I think the `import` design you propose is a bit more complicated than it 
> needs to be. Python and Haskell get by just having "import everything" and 
> "import itemized (with aliases)". I don't see the need for 'hiding'; if you 
> have a rule that itemized imports get priority over import-everything, then 
> that covers the most important use case of selectively shadowing one module's 
> imports with another. Bikeshed-wise, I don't see much reason to veer from the 
> Java/Haskell-ish template of:
> 
> import Foo.* // import everything from module Foo
> import Foo.(x, y, z as zed) // import x, y, and z from foo, renaming Foo.z to 
> zed
> 
> -Joe
> 
>> On Jul 18, 2016, at 2:09 PM, Robert Widmann via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> Hello all,
>> 
>> TJ Usiyan, Harlan Haskins, and I have been working on a proposal to rework 
>> qualified imports and introduce an explicit module system to Swift that we’d 
>> like to publish for your viewing pleasure.
>> 
>> The initial impetus was set out in a radar (rdar://17630570) I sent fairly 
>> early on that didn’t receive a response, so I started a swift-evolution 
>> thread discussing the basics of this proposal.  It has been refined and 
>> expanded a bit to include an effort to make Swift modules explicit and 
>> updated with the feedback of that first thread.  Contents of the proposal 
>> are inline and can also be had as a gist or on Github.
>> 
>> Cheers,
>> 
>> ~Robert Widmann
>> 
>> Qualified Imports and Modules
>> 
>>      • Proposal: SE-NNNN
>>      • Authors: Robert Widmann, Harlan Haskins, TJ Usiyan
>>      • Status: Awaiting review
>>      • Review manager: TBD
>> Introduction
>> 
>> We propose a complete overhaul of the qualified imports syntax and semantics 
>> and the introduction of a module system.
>> 
>> Motivation
>> 
>> Swift code is modular by default. However, it is not clear how to decompose 
>> existing modules further into submodules. In addition, it is difficult to 
>> tell how importing a module affects its export to consumers of a library. 
>> This leads many to either fake namespaces with enums, attempt to structure 
>> Swift code with modulemaps, or use a large amount of version-control 
>> submodules. All of these can be rolled into one complete package in the form 
>> of a comprehensive rethink of the qualified import system and the 
>> introduction of a module system.
>> 
>> Proposed solution
>> 
>> Modules will now become an explicit part of working with canonical Swift 
>> code. The grammar and semantics of qualified imports will change completely 
>> with the addition of import qualifiers and import directives. We also 
>> introduce three new contextual keywords: using, hiding, and renaming, to 
>> facilitate fine-grained usage of module contents.
>> 
>> Detailed design
>> 
>> Qualified import syntax will be revised to the following
>> 
>> module-decl -> module <module-path>
>> import-decl -> <access-level-modifier> import <module-path> <(opt) 
>> import-directive-list>
>> module-path -> <identifier>
>>            -> <identifier>.<import-path>
>> import-directive-list -> <import-directive>
>>                      -> <import-directive> <import-directive-list>
>> import-directive -> using (<identifier>, ...)
>>                 -> hiding (<identifier>, ...)
>>                 -> renaming (<identifier>, to: <identifier>, ...)
>> 
>> This introduces the concept of an import directive. An import directive is a 
>> file-local modification of an imported identifier. A directive can be one of 
>> 3 operations:
>> 
>> 1) using: The using directive is followed by a list of identifiers within 
>> the imported module that should be exposed to this file. 
>> 
>> // The only visible parts of Foundation in this file are 
>> // Date.init(), Date.hashValue, and Date.description.
>> import Foundation.Date using (Date.init(), Date.hashValue, Date.description)
>> 2) hiding: The hiding directive is followed by a list of identifiers within 
>> the imported module that should be hidden from this file.
>> 
>> // Imports all of Foundation.Date except `Date.compare()`
>> import Foundation.Date hiding (Date.compare())
>> 3) renaming: The renaming directive is followed by a list of identifiers 
>> separated by to: that should be exposed to this file but renamed. 
>> 
>> // Imports all of Dispatch.DispatchQueue but renames the static member 
>> // DispatchQueue.main, to DispatchQueue.mainQueue
>> import Dispatch.DispatchQueue renaming (DispatchQueue.Type.main to: 
>> DispatchQueue.Type.
>> mainQueue)
>> 
>> // Renaming can also rename modules.  All members of UIKit have to be 
>> qualified with
>> // `UI` now.
>> import UIKit renaming (UIKit, to: UI)
>> Import directives chain to one another and can be used to create a 
>> fine-grained module import:
>> 
>> // Imports all of Foundation except `DateFormatter` and renames `Cache` to 
>> `LRUCache`
>> import Foundation
>> hiding (DateFormatter) renaming (Cache to: LRUCache)
>> 
>> // Imports SCNNode except SCNNode.init(mdlObject:) and renames 
>> `.description` to
>> // `.nodeDescription` 
>> import SceneKit
>> using (SCNNode) 
>>                renaming (SCNNode
>> .description, to: SCNNode.
>> nodeDescription)
>>                hiding (SCNNode
>> .init(mdlObject:))
>> Directive chaining occurs left-to-right:
>> 
>> // This says to 1) Hide nothing 2) Use nothing 3) rename Int to INT.  It is 
>> invalid
>> // because 1) We will show everything 2) Then hide everything 3) Therefore 
>> Int is unavailable, error.
>> import Swift hiding () using () renaming (Int
>> , to: INT)
>> 
>> // This says to 1) Use Int 2) Hide String 3) rename Double to Triple.  It is 
>> invalid
>> // because 1) Int is available 2) String is not, error. 3) Double is 
>> unavailable, error.
>> import Swift using (Int) hiding (String) renaming (Double
>> , to: Triple)
>> 
>> // Valid.  This will be merged as `using (Int)`
>> import Swift using () using (Int
>> )
>> 
>> // Valid.  This will be merged as `hiding (String, Double)`
>> import Swift hiding (String) hiding (Double
>> ) hiding ()
>> 
>> // Valid (if redundant). This will be merged as `using ()`
>> import Swift using (String) hiding (String)
>> Module scope is delimited by the keyword module followed by a fully 
>> qualified name and must occur as the first declaration in a file. For 
>> example:
>> 
>> // ./Math/Integers/Arithmetic.swift
>> 
>> module Math
>> .Integers.
>> Arithmetic
>> 
>> 
>> public protocol
>> _IntegerArithmetic {}
>> 
>> 
>> public struct
>> _Abs {}
>> 
>> 
>> @_versioned
>> internal func _abs<Args>(_ args: Args) ->
>> (_Abs, Args) {}
>> 
>> 
>> // ./Math/Integers.swift
>> 
>> module Math
>> .
>> Integers
>> 
>> 
>> // _abs is visible in this module and all others within the project, 
>> // but is not exported along with it.
>> internal import Math.Integers.Arithmetic
>> 
>> 
>> 
>> public protocol IntegerArithmetic : _IntegerArithmetic, Comparable
>> {}
>> 
>> public protocol SignedNumber : Comparable
>> , ExpressibleByIntegerLiteral {}
>> 
>> 
>> 
>> // Math.swift
>> 
>> module Math
>> 
>> 
>> // Exports the entire public contents of Math.Integers, but nothing in 
>> // Math.Integers.Arithmetic.
>> public import Math.Integers
>> Modules names are tied to a directory structure that describes their 
>> location relative to the current module and it will now be an error to 
>> violate this rule. For example:
>> 
>> module String // lives in ./String.swift
>> 
>> module 
>> String.Core // lives in ./String/Core.swift
>> 
>> module 
>> String.Core.Internals.Do.You.Even.Write // lives in 
>> ./String/Core/Internals/Do/You/Even/Write.swift
>> Existing projects that do not adopt these rules will still retain their 
>> implicit module name (usually defined as the name of the framework or 
>> application that is being built) and may continue to use whatever directory 
>> structure they wish, however they may not declare any explicit modules.
>> 
>> This proposal also solves the problem of module export. A module that is 
>> imported without an access level modifier will default to an internal import 
>> per usual. However, when it is useful to fully expose the public content of 
>> submodules to a client, a public modifier can be used. Similarly, when it is 
>> useful to access internal or [file]private APIs, but not expose them to 
>> clients, those access modifiers may be used. The rule of thumb is: Only 
>> identifiers that are at least as visible as the qualifier on the import make 
>> for valid import declarations. For example:
>> 
>> // A submodule declaring a `private` class that gets imported with 
>> // an `internal` qualifier with a `using` directive is an invalid import 
>> // declaration.  
>> 
>> module Foo
>> .
>> Bar
>> 
>> 
>> private class
>> PrivateThing {}
>> 
>> module Foo
>> 
>> 
>> // Error: PrivateThing not visible, use `private import`
>> import Foo.Bar using (PrivateThing) 
>> // However, a submodule declaring a `public` struct that gets imported with 
>> // an `private` qualifier is a valid import declaration.
>> 
>> module Foo
>> .
>> Bar
>> 
>> 
>> public class
>> PublicThing {}
>> 
>> module Foo
>> 
>> 
>> // All good!  Foo can see Foo.Bar.PrivateThing.
>> private import Foo.Bar using (PublicThing) 
>> Because import directives are file-local, they will never be exported along 
>> with a public import and will default to exporting the entire contents of 
>> the module as though you had never declared them.
>> 
>> // In this file and this file alone, the directives apply.  To the user
>> // of this module, it is as though this declaration were simply:
>> // public import Foundation.Date
>> public import Foundation.Date hiding (Date.init
>> ()) 
>>                              renaming (Date
>> .Type.
>> distantPast, 
>>                                        to: Date
>> .Type.
>> letsGoLivingInThePast,
>>                                        Date
>> .Type.
>> timeIntervalSinceReferenceDate, 
>>                                        to: Date
>> .Type.
>> startOfTheUniverse)
>>                              renaming (Date
>> .Type.<, to: Date.Type.<<<<<)
>> Impact on existing code
>> 
>> Existing code that is using qualified module import syntax (import 
>> {func|class|typealias|class|struct|enum|protocol} <qualified-name>) will be 
>> deprecated. Code that is not organized into modules will remain unaffected 
>> and organized into one contiguous top-level module. However, it is strongly 
>> recommended that frameworks be decomposed and reorganized around the new 
>> module system.
>> 
>> As a case study, the public interface to the standard library appears to 
>> already be mostly broken down into submodules as described in GroupInfo.json.
>> 
>> Code that is defined in modulemaps already defines a module structure that 
>> can be imported directly into this scheme.
>> 
>> Alternatives considered
>> 
>> Module export can also be placed on the module declaration itself. The 
>> relevant parts of the grammar that have changed are below with an example:
>> 
>> module-decl -> <access-level-modifier> module <module-path>
>> import-decl -> import <module-path> <(opt) import-directive-list>
>> 
>> private module String.Core.
>> Internals
>> 
>> 
>> // Shh, it's a secret.
>> While this style makes it immediately obvious to the library author which 
>> modules are public or private, it causes the consumer problems because 
>> submodule exports are no longer explicit and are entirely ad-hoc. In the 
>> interest of enabling, for one, users of IDEs to drill into public 
>> submodules, making export local to import seems more appropriate.
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to