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

Félix Cloutier felixcca at yahoo.ca
Thu Jul 21 10:17:39 CDT 2016


I know that the compiler can't read my mind. I don't mean to be frustrating.

If Foundation is imported in the bridging header of a project (as it is today, by default, in Swift framework projects), you get all of Foundation in all of your Swift code without a chance to write "import Foundation hiding (...)" anywhere. This reinforces my position that types should be selected affirmatively.

I'm not proposing a better solution because I don't have one right now. But if it would help appease you that I suggest something: keep "import using", let go of "hiding", and reuse the "using" keyword to select symbols from specific modules to break ambiguities. (Names must always be module-qualified to break ambiguities with classes that have the same name as a module.)

> import Foo
> import Bar
> 
> using Foo.Baz; // in case of ambiguity, pick Foo.Baz
> using extension Bar.Date; // in case of ambiguity on any Date extension method, pick the one in Bar
> using extension Foo.Date.frob; // except for frob, that one comes from Foo

I know that this has problems on its own. Notably, `using` can't be a contextual keyword, the identifier now has to be reserved.

Félix

> Le 20 juil. 2016 à 23:51:15, Robert Widmann <rwidmann at apple.com> a écrit :
> 
> 
>> On Jul 20, 2016, at 9:37 PM, Félix Cloutier via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> The problem is that by specifying "import Foo using (Baz)", I get nothing else from Foo. If I only want to exclude one conflicting name, I would have:
>> 
>>> import Foo
>>> import Bar hiding (Baz)
>> 
>> In case of a conflict, my "internal monologue" is more like "take Baz from Foo" than "don't take Baz from Bar".
>> 
> 
> How else would you resolve an ambiguity than by selecting the appropriate declaration and hiding the others?  Swift’s semantic analysis cannot read your mind, and neither can your (or mine) proposal for renaming syntax - in that you still have to import both modules either way.  You may as well be explicit about which name you’re actually using and which ones you’re actually hiding, eh?
> 
>> Félix
>> 
>>> Le 20 juil. 2016 à 20:46:18, Robert Widmann <devteam.codafi at gmail.com <mailto:devteam.codafi at gmail.com>> a écrit :
>>> 
>>> 
>>> 
>>> ~Robert Widmann
>>> 
>>> 2016/07/20 20:07、Félix Cloutier via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> のメッセージ:
>>> 
>>>> My understanding is that we want "using" and "hiding" because we want the ability to either take just a few things OR leave out just a few things. With a unified "import Foo (A = B, C = D, E = _) syntax, we only get the ability to take a few things AND hide a few things.
>>> 
>>> Again, renaming is not something I want done with the same syntax as introducing and removing things from scope because they are distinct operations.  This import tells me nothing from a semantic perspective and just seems easy to type rather than understand.  Nowhere in the language can you find something that resembles this either.
>>> 
>>>> 
>>>> I've never really been into a case where I badly had to *not* import a name, so while I see why it makes sense from a mathematical perspective to have "hiding", I'm not sure how much I'd miss it if it wasn't there.
>>>> 
>>>> I realize that it solves the ambiguous type problem <https://bugs.swift.org/browse/SR-898>, but I consider that it's a flawed solution. Instead of specifying from which module you want an import, you have to specify on which modules you don't want it.
>>> 
>>> You still specify which module you want to import from, so I don't see your point here.  Given that Foo and Bar both define a class Baz, here's your import
>>> 
>>> import Foo using (Baz)
>>> import Bar hiding (Baz)
>>> 
>>> What's the problem here?  Isn't this exactly what you wanted to say in English (or whatever internal monologue you might have) spelled out in code?  It scales immediately to multiple ambiguities and we can provide diagnostics to insert or remove identifiers in these lists to help the user out when they get stuck with an insufficiently inclusive or exclusive import list.  The Python example is much more difficult to reason about from my perspective and from the perspective of the compiler.  In fact, it's almost the code that's needed today to work around this problem - we're trying to fix the need for this here.
>>> 
>>>> 
>>>> To see if we can get inspiration, I'd like to pitch an imperfect Python-like approach, where you could import a module as a namespace (and then you'd always have to write Module.Class, with modules systematically shadowing classes in the global namespace), or in addition to that, import every top-level name in the module into the file's global namespace. Names defined in multiple modules remain ambiguous unless explicitly shadowed:
>>>> 
>>>>> private typealias OrderedSet = BTree.OrderedSet
>>>>> private var foo: (Int) -> Int = Bar.foo
>>>> 
>>>> You would not be allowed to shadow a module with a class.
>>>> 
>>>> This, however, still does not solve the extension problem. Additionally, given that the default visibility for top-level names is internal, careless users could easily pollute the project's global namespace. Finally, for micro-frameworks that have a class with the same name as a module, you'd always have to write Name.Name, since the class can't shadow the module.
>>>> 
>>>> Félix
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto: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/4d1a7f73/attachment.html>


More information about the swift-evolution mailing list