>  is changed so that, outside the module, it has a member `frobnicate()` and 
> no longer has a member `bobnicate()`?

*Unchanged.  Other than that, you’ve got it!  I wanted to make *very* sure that 
whatever APIs come in are the same ones that go out regardless of local changes.

> On Jul 18, 2016, at 3:17 PM, Xiaodi Wu <[email protected]> wrote:
> 
> On Mon, Jul 18, 2016 at 5:09 PM, Robert Widmann <[email protected] 
> <mailto:[email protected]>> wrote:
> 
>> On Jul 18, 2016, at 3:00 PM, Xiaodi Wu <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>> On Mon, Jul 18, 2016 at 4:49 PM, Robert Widmann <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>>> On Jul 18, 2016, at 2:32 PM, Xiaodi Wu <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> 
>>> This is an interesting document. I think it deserves careful study. For 
>>> now, some questions:
>>> 
>>> What is the rationale behind permitting the using of specific methods? This 
>>> seems to be usually fine-grained in comparison to other languages. What use 
>>> cases do you have in mind for this?
>>> 
>> 
>> One use case: Swift libraries export not just member references as I’ve used 
>> here, but a large amount of free functions.  It has long been a problem that 
>> free functions seem to pollute a shared namespace and there didn’t seem to 
>> be a clear way to hide them.
>> 
>> Would a plausible simplification of the proposal be to have it fine-grained 
>> enough to address free functions but not methods inside types?
>> Incidentally, although I do not see it in the proposal, I assume that * in 
>> some form will be permitted (as in, `import Foundation using *`).
>> 
>> 
>>> I can see the use case for hiding specific symbols when they come into 
>>> conflict with your own, but in your example you're hiding specific methods 
>>> declared *in* an imported type. What is the use case here? Is it going to 
>>> allow me to open backdoors so that, if I don't like `Foo.frobnicate()`, I 
>>> can hide it and then substitute my own in an extension? This seems like a 
>>> bad thing at first blush.
>> 
>> For members that would be an acceptable use-case.  The worst-case scenario 
>> that comes to mind is this being used as a way to “virtually override” a 
>> method in a subclass.  Then again, the scope of the damage is limited to the 
>> file in which you’ve declared this monstrosity so clients and even you will 
>> not be able to see it outside of there unless you explicitly redeclare the 
>> hiding import (in which case, you probably know what you’re doing).
>> 
>> A use care here might be hiding the KVO-ish parts of an object from 
>> yourself, or more generally subsetting out the part of an API you know you 
>> shouldn’t interact with in a particular submodule.
>> 
>>> 
>>> I can see the obvious use case for renaming modules and types on 
>>> import--basically, in my mind, it's like typealiases with hiding, and it's 
>>> available in other languages of course. But how would renaming methods 
>>> work? If Foo conforms to Equatable and I rename `Foo.==` to `Foo.!=`, is 
>>> the type I import still Equatable? How would it behave? And even if Foo is 
>>> fine, what happens if I try to subclass my Frankensteinian Foo?
>> 
>> Of course you still conform to Equatable.  The renaming defines a mapping 
>> from your names to “proper" names.  For example, if you use a renaming 
>> import to change the requirements of a protocol in a file, then your 
>> conformance will simply look at the mapping and see that everything resolves 
>> into its proper place.  Bear in mind that your renamings will not survive 
>> outside of the file in which you declare them.  Frankenteinian Foo exists 
>> where you say it does and nowhere else.  Everybody else just sees Foo 
>> conform to Equatable (unless they rename things themselves).
>> 
>> Maybe let's work through an example:
>> 
>> Suppose we have in stdlib:
>> 
>> ```
>> public protocol FooProtocol {
>>   func frobnicate()
>> }
>> ```
>> 
>> Now, I write a library:
>> 
>> ```
>> import Swift.FooProtocol renaming (FooProtocol.frobnicate(), to: 
>> FooProtocol.bobnicate())
>> 
>> public open class MyFoo : Swift.FooProtocol {
>>   public open func bobnicate() {
>>     print("Does your head hurt yet?")
>>   }
>> }
>> ```
>> 
>> Now, you are an end user of my sinister library.
>> 
>> What is the public API of `MyFoo`?
> 
> The proposal addresses this
> 
> > 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.
> 
> The user (and even you in other files that import this module) will see a 
> protocol conformance exactly as laid out in the Swift.FooProtocol module.
> 
>> For you, does `MyFoo` conform to `Swift.FooProtocol`?
> 
> It conforms because the renaming you wrote describes a way of resolving 
> FooProtocol.bobnicate() (your API) to FooProtocol.frobnicate() (everybody 
> else’s API).
> 
>> Can you call `MyFoo.frobnicate()`? How about `MyFoo.bobnicate()`?
>> 
>> What if you try to subclass `MyFoo`?
> 
> If you are inside the module you wrote the renaming, you will use it.  If you 
> are outside of it, you will see the protocol requirement sans renaming.
> 
>> Does your subclass still conform to `Swift.FooProtocol`?
>> Do you override `bobnicate()` or `frobnicate()`?
>> My head hurts…
> 
> Because you have explicitly renamed the protocol requirement, you will 
> override the same protocol requirement both inside and outside this module 
> but your renaming will not propagate to other files unless they themselves 
> opt in the way you have here.  It would be particularly sinister if you could 
> arbitrarily edit the user-facing API of members simply by importing a library.
> 
> Sounds good. If I understand you correctly, by conforming `MyFoo` to an 
> internally renamed `Swift.FooProtocol`, the renaming of the user-facing API 
> for `FooProtocol` means that the public API of `MyFoo` is changed so that, 
> outside the module, it has a member `frobnicate()` and no longer has a member 
> `bobnicate()`?
> 
> 
>>  
>> 
>>> 
>>> On Mon, Jul 18, 2016 at 16:10 Robert Widmann via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> 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 
>>> <http://permalink.gmane.org/gmane.comp.lang.swift.evolution/1378> 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 
>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6> or on 
>>> Github. <https://github.com/apple/swift-evolution/pull/440>
>>> 
>>> Cheers,
>>> 
>>> ~Robert Widmann
>>> 
>>> Qualified Imports and Modules
>>> 
>>> Proposal: SE-NNNN 
>>> <https://gist.github.com/CodaFi/NNNN-first-class-qualified-imports.md>
>>> Authors: Robert Widmann <https://github.com/codafi>, Harlan Haskins 
>>> <https://github.com/harlanhaskins>, TJ Usiyan 
>>> <https://github.com/griotspeak>
>>> Status: Awaiting review
>>> Review manager: TBD
>>>  
>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#introduction>Introduction
>>> 
>>> We propose a complete overhaul of the qualified imports syntax and 
>>> semantics and the introduction of a module system.
>>> 
>>>  
>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#motivation>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.
>>> 
>>>  
>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#proposed-solution>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.
>>> 
>>>  
>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#detailed-design>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.<<<<<)
>>>  
>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#impact-on-existing-code>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 
>>> <https://github.com/apple/swift/blob/master/stdlib/public/core/GroupInfo.json>.
>>> 
>>> Code that is defined in modulemaps already defines a module structure that 
>>> can be imported directly into this scheme.
>>> 
>>>  
>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#alternatives-considered>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
>>> [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

Reply via email to