> On Jul 18, 2016, at 4:34 PM, Brent Royal-Gordon <[email protected]> > wrote: > >> On Jul 18, 2016, at 2:09 PM, Robert Widmann via swift-evolution >> <[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. > > This is really interesting. A few incomplete comments: > >> 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()) > [snip] >> // Exports the entire public contents of Math.Integers, but nothing in >> // Math.Integers.Arithmetic. >> public import Math.Integers > > Would this work? > > module UIKit > > public import UIKit.UIGestureRecognizerSubclass.UIGestureRecognizer > hiding (UIGestureRecognizer.touchesBegan(_:with:), > UIGestureRecognizer.touchesMoved(_:with:), …) > > (If so, we'd need a way to hide only the setter of a property, not the > getter.)
Yes, that would work. Notation for hiding setters and getters through the import system (probably best to do it internally, but I see what you mean) can ideally be another dot qualifier public import Foo hiding (Foo.bar) // Hide the whole thing public import Foo hiding (Foo.bar.set) // Hide the setter. public import Foo hiding (Foo.bar.get) // Hide the getter [Not sure why you’d want this]. >> 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 > > I think this is a mistake for several reasons: > > * You may need to split a single submodule across multiple files, but this > rule doesn't allow that. > > * The module declaration and filename contain redundant information, and one > of them could get out of sync with the other. > > * Xcode doesn't like to organize things into folders on disk and will fight > you tooth and nail. > > * Deeply nested folders are a usability issue. Never forget the jury in > Oracle v. Google: > https://www.geek.com/wp-content/uploads/2016/05/courtroomhijinks.png > > At the very least, I would like to see allowances for multi-file > submodules—String/Core/Internals/Do/You/Even/Write**.swift. Better would be > to use long filenames—String.Core.Internals.Do.You.Even.Write*.swift. Even > better would be to just allow freeform naming and trust programmers to > organize their projects sanely. We are not proposing a Java-style module system so much as an extension of the existing one to submodules the way they are used today for frameworks like Darwin. Projects no longer require reverse-DNS-style directory structures and nesting of submodules to great depth can grow unwieldy, but that may be a sign that a project is growing too decentralized. Large frameworks will decompose themselves into submodules in roughly the same way that projects written in Objective-C, C, C++ have always decomposed themselves. The directory structure for that style of framework rarely grows to the extend you’re concerned with here. >> 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. > > It appears the semantics here are "grab all declarations at level X and > above, and expose them in this module as level X". This is bizarre for a > number of reasons: > > * Currently, `import` can only access `internal` declarations using > `@testable`. This would change that. > It would not. Re-export can only re-export public APIs. > * Currently, `import` can't access `private` and `fileprivate` declarations > at all, and it's not clear what it would mean to add that. What happens if > two different parts of the module have different `private` members with the > same name? Which do you get? If we decide to allow this you will get an ambiguity which you can resolve with a renaming. John has made me reconsider the semantics of a private import. > * Currently, `import` only affects the current file—it's effectively "import > `public` members as `fileprivate`". If your default is `internal import`, > that would imply that an import statement in one file would, by default, > expose the APIs it imported to all files. That's an important change in > behavior. > It changes existing behavior in the sense that internal imports are now module-scoped rather than project-scoped but you still cannot re-export non-public APIs. I specifically want to *remove* the behavior where an imported API winds up recursively importing submodules until your qualified import is just garbage anyway. Your submodules will not see an `internal import` in the same way that a project can currently see an internal import unless they themselves declare an `internal import` of that module. And if they’re re-exporting public APIs then you probably wanted to see that when you imported them anyway. > I think you're mixing two things together that ought not to be. `import` > should always import only public APIs (unless you use `@testable`—which might > need a bit of renaming to support the additional use case of SPIs between > submodules and supermodules—in which case you also get `internal` APIs). And it does. > An access modifier on the `import` statement controls how they're exposed to > the rest of the file/project/world, and `private` is the default. It's a > little weird to have `private` be the default on `import` when `internal` is > the default on everything else, but the alternative is to change `import`'s > behavior in a way that is neither backwards-compatible, nor likely to be > correct. Internal is the default. > 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. Doesn’t mean you can import internal APIs from modules you don’t own (that’s still banned). You can still only export public API. > >> 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. > > Whoa, wait, what? Why? I think hiding parts of the implementation is a good > use case for re-exporting a module. And I think the clear implication of > attaching these clauses directly to the import statement is that it controls > how the module is imported everywhere that statement makes it visible, not > just within the one file. If we're not going to do that, I think these > clauses ought to be separated from the `import` statement and turned into > something separate. > > -- > Brent Royal-Gordon > Architechies >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
