[swift-evolution] [Proposal][Discussion] Qualified Imports

Robert Widmann devteam.codafi at gmail.com
Thu Jul 21 10:59:30 CDT 2016



~Robert Widmann

2016/07/21 3:19、Pyry Jahkola via swift-evolution <swift-evolution at swift.org> のメッセージ:

> I think we're getting somewhere.
> 
>>> On 21 Jul 2016, at 12:01, Robert Widmann <rwidmann at apple.com> wrote:
>> 
>>>> (An excerpt about the hiding directive)
>>> 
>>> 4. Hmm, the above design detail is easily missed when reading the proposal. So what you're proposing is that the hiding of Date essentially turns Date into a type that the code will know almost nothing about, except it's something we can pass to other types' methods that expect a Date, am I right?
>>> 
>>> What's the benefit in that? Do you anticipate it will make importing lighter somehow, possibly improving compilation or library loading speed? You mentioned something along those lines in the Motivation, but I'm not sure if I got it right here.
>> 
>> It is so that use of an API in a framework like Foundation does not necessitate polluting your Swift files with a million using imports - thus defeating the purpose of this proposal.
> 
> You explained further below what else `hiding` imports can be used for. But my comment was motivated by your example of `import Foundation hiding (Date)`. 
> 
> I fail to see how the lack of `hiding` imports would imply Swift files with a lot using imports. In my counting, they amount to at most one extra using import. (And I propose ~10 lines below what would get that to zero.)
> 
> The simple reason I could see someone write `import Foundation hiding (Date)` is because another imported module "Julian" she uses happens to export another Date type which she wants to use instead. And if we could just as well solve that use case by making it so that
> 
>     import Foundation
>     import Julian, Julian using (Date)
>     assert(Date.self == Julian.Date.self)
> 
> brings in both modules but makes Julian.Date the one that Date is shorthand of.
> 
> Besides, Joe and friends offered the use of `*` to mean "and everything else", which is problematic because `*` also happens to be an operator function name. But we could make it so that the underscore imports everything else (without explicit qualification), making the above example exactly equivalent to:
> 
>     import Foundation using (_)   // same as `import Foundation`
>     import Julian using (_, Date) // bring in Date explicitly and all else implicitly
>     assert(Date.self == Julian.Date.self)

Funny, others have been suggesting _ be used as a special namespace to hide identifiers in.  It implies you don't care about identifiers, not that you want all of them.

> 
> 
>> DateFormatter alone needs to know about Date, String, TimeInterval, Calendar, Locale, and TimeZone.  Each of those needs to know about additional components.  To require an import decl to use these types explicitly would be madness.  You'd just wind up importing Foundation anyway.
> 
> "You'd just wind up importing Foundation anyway" is an argument that doesn't seem imply from the given Motivation section AFAICT.

I should be more clear: If we requires you to qualified import types without these allowances then you would have to recursively import types out of Foundation until you wind up importing the whole thing anyway.  To be able to use DateFormatter you shouldn't have to tell Swift you also want to use Date, String, TimeInterval, etc.  We know you want to, we can see all of these identifiers.  When the time comes for you to pick a member on Date, then you want a using or hiding import to let us know you want to see it.

> 
> I can see three kinds of problems here (objective or subjective), caused by importing the whole Foundation:
> Identifier name conflicts, which we could solve with just the `import Module using (name, Name, _)` syntax, essentially indicating which Module should be preferred.
The grammar makes no allowances for types to be imported there, only qualified module name.  Not sure what you mean.
> 
> Identifier names shadowing module names, where e.g. a `private enum Foundation {}` disables the fully qualified access to the Foundation module's API). This remains an unsolved problem, but the introduction of qualified module imports `import Foundation as Foundation` or `import Foundation as F` (or, heh, `import Foundation as is`) would be one way of going about it.

And additive and can be introduced in a future proposal as a new directive on top of this system.  We wanted this, the community had reservations, we backed off.
> 
> Auto-completer "hygiene", or being explicit which part of a large imported API is not considered appropriate to use by the author
> Point 3 is the only problem that `hiding` imports could be uniquely used for, especially if they can be narrowed down to members of imported types and extensions (e.g. Swift.String.UTF8View, as given in the proposal). But is that worth having?

We need to be able to disambiguate more than just top-level names, for one.  Hiding can do that.

> 
> 
>>> 5. These chaining rules do fit on the back of a napkin, but I'm not sure if we need them at all. I'm not convinced we need `hiding` imports, and without hiding imports, we need no rules for the order of imports.
>> 
>> How else are we to allow you to import a using type but not any of its member types?
> 
> I don't know. I'm asking "why?" not "how?"

That is why, just rhetorical.

> 
> 
>> How could we support removing APIs related to NSCell in AppKit apps? How about NSStream everywhere else? How else can we allow, in the future, the ability to import NSObject but none of its KVO-related members?
> 
> I'm saying you should explain this in the Motivation. Or consider moving the `hiding` import syntax into a further proposal.

Fair.

> 
> 
>> A hiding import is an invariant: It says a particular API should never be considered for use in this file.  The very act of 'using' an identifier means you are hiding all others.  The very act of 'hiding' an identifier means you are using all others.
> 
> That is very logical. But it would be better if there was a real-world example use case given where the use of `hiding` was a clear win over a combination of `import` and `import ... using (...)`. The current one about Date isn't very convincing because instead of hiding one, it could be solved by highlighting (using) the other.

I have given one.  Show me how to express the "give me String but not String.UTF8View" example without hiding?

> 
> 
>>> What I will keep suggesting is that `using` imports actually take up the name in the file-local scope such that nothing else in the same file's scope — be it another `import ... using (...)`, a local type declaration, function, or value — can declare the same name with a different meaning. That way, a plain
>>> 
>>>     import Foo
>>> 
>>> can import everything from Foo, while another
>>> 
>>>     import Foo using (Bar)
>>> 
>>> can be used to explicitly choose the Bar the code is about to use.
>> 
>> That was the plan.  You will receive an "invalid redeclaration" error as always. 
> 
> 👍!
> 
> — Pyry
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160721/4892b97d/attachment.html>


More information about the swift-evolution mailing list