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

Xiaodi Wu xiaodi.wu at gmail.com
Wed Jul 20 18:17:20 CDT 2016


On Wed, Jul 20, 2016 at 4:57 PM, Robert Widmann <rwidmann at apple.com> wrote:

>
> On Jul 20, 2016, at 2:52 PM, Robert Widmann via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
> On Jul 20, 2016, at 2:35 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
>
>
> On Wed, Jul 20, 2016 at 4:24 PM, Robert Widmann <rwidmann at apple.com>
> wrote:
>
>>
>> On Jul 20, 2016, at 2:19 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>> On Wed, Jul 20, 2016 at 4:06 PM, Robert Widmann <rwidmann at apple.com>
>> wrote:
>>
>>>
>>> On Jul 20, 2016, at 2:04 PM, Robert Widmann via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>
>>> On Jul 20, 2016, at 1:59 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>
>>> Why is hiding in-scope but renaming out-of-scope?
>>>
>>>
>>>
>>> Because hiding and renaming can be used in combination to subset out
>>> APIs, not alter them.
>>>
>>>
>>> I mistyped.  Should be "Because hiding and using can be used in
>>> combination to subset out APIs, not alter them."
>>>
>>
>>
>> Sure, I buy that.
>>
>> Both are additive to Swift,
>>>
>>>
>>> As part of this proposal, both are source-breaking.
>>>
>>>
>> I don't see how. If hiding were cut from the proposal, adding it later
>> with even the exact syntax you propose should break no pre-existing
>> code--am I wrong?
>>
>>
>> Renaming the way we originally laid it out would certainly be additive.
>> The way you have it laid out would overlap a bit with hiding, sure, but it
>> is still additive and (IMO, but I’m probably among a tiny minority of users
>> that has used a proof assistant’s syntax as the basis for a proposal!) a
>> good thing to have.
>>
>
>
> Sorry, I fear I've incorrectly communicated the point I was trying to
> make. I'm not advocating here for inclusion of renaming as part of this
> proposal. I simply think that--even though I buy your claim that hiding and
> using both subset out APIs--hiding has more affinity with renaming and the
> two facilities probably ought to be considered together, whenever that is.
>
> Thus, I'm suggesting that it would be feasible to postpone discussion of
> hiding until such future time as a fully fleshed out renaming scheme is
> proposed. A revamped source-breaking import syntax without either hiding or
> renaming could be put in place now, and future addition of hiding and/or
> renaming would not have to be source-breaking. Is there something wrong
> with this argument?
>
>
> There is still a useful to distinction to be made between explicitly
> renaming an API and explicitly hiding an API.  Scala’s syntax to rename to
> underbar is a convenient notation for that kind of thing, but it goes
> against making qualified imports explicit and it means that renaming
> necessarily has to import identifiers into scope as well as rename them.
> What the OP (maybe it was you, sorry if it was) meant by “equivalent”
> missed the point that
>
> import Swift hiding (String)
>
> doesn’t translate into
>
> import Swift renaming (String, to: _)
>
> it translates into
>
> import Swift hiding () renaming (String, to: _)
>
> Renaming introducing identifiers into scope seems like a phase-shift and
> is not something the verb “rename” implies should happen here.  It’s an
> interesting little hole in Agda’s module system that you can use
>
> open A hiding (xs) renaming (ys to zs)
>
> to mean
>
> open A using (A; xs; ys) renaming (ys to zs)
>
>
> Actually, scratch that.  Their documentation explicitly mentions that
> hiding and renaming may not be mixed because of the phase distinction and
> recommend the using translation above as the way to go.
>


This is very illuminating. I think I've rather misunderstood what it is
you're proposing. I wonder if others did also.

The syntax you proposed seemed cumbersome to me because my mental model of
importing (informed by my probably superficial understanding of vanilla
procedural programming languages) has only one phase: importing. This is
why I proposed radically simplifying the spelling. To me, all of these
operations are just sugar on a single import phase, where "stuff" from
outside the module is "brought into" the module, either with the same name
("using"), a different name ("renaming"), or no name ("hiding").

But what you're saying here--if I understand correctly--is that you're
proposing a multi-phase import system, where the possible phases, which can
be composed in varying orders, are "using", "hiding", and "renaming". This
is much, much more elaborate than I had contemplated. So beyond the
bikeshedding of syntax, I'd ask: why do we need this multi-phase model of
importing?



>
>
>>
>> and as has been argued by others, the former is a special case of the
>>> latter.
>>>
>>>
>>> A special case that cannot cause large-scale file-relative changes to
>>> APIs.  Renaming is primarily used in other languages that treat free
>>> functions as more canonical than we do, or allow operator definitions that
>>> can be used as notation.
>>>
>>>
>> I don't know about 'primary use,' but the most common use I've
>> experienced in Python, for example, is the mundane task of importing module
>> Foo2 as Foo.
>>
>>
>>
>> And I still want that kind of syntax.  I just want to get the breaking
>> changes out of the way to make room for it in the future.
>>
>
>
> Right. See above about my argument as to which parts of your proposal have
> to be source-breaking, and which don't.
>
>
>
>> In those cases, you often have your own notation you’d like to use.  In
>>> Swift, such changes should be rare enough that if you can’t solve them with
>>> a disambiguating qualified import then you can just redeclare the
>>> identifier some other way (typealias, top-level let, wrapper class,
>>> whatever).
>>>
>>>
>> You've already stripped out renaming of members from the proposal. I
>> agree wholeheartedly. The only flavor of renaming I'm thinking of here is
>> equivalent to a fileprivate typealias and hiding, which cannot be done in
>> this version of the proposal because hiding always comes before
>> typealiasing and you can't typealias what isn't imported. It isn't about
>> altering APIs any more than a fileprivate typealias can be thought of as
>> altering APIs.
>>
>>
>> In the sense that you can’t use the original identifier if you rename it,
>> it is an alteration.  John brought up a great point about exporting these
>> things and how it could be a potentially dangerous thing.  Even used
>> locally, there’s the potential for people to specify 500 lines of import
>> renaming crap that has to be copypasta’d throughout the codebase to
>> maintain that particular style - not a use-case I’ve ever seen, but the
>> potential is there.
>>
>
>
> This is, I think, a spurious argument. I can equally have 500 lines of
> private typealiased crap that has to be copypasta'd.
>
>
>
>>
>>
>>> On Wed, Jul 20, 2016 at 15:55 Brandon Knope <bknope at me.com> wrote:
>>>
>>>> I meant is there any reason for requiring parentheses
>>>>
>>>> On Jul 20, 2016, at 4:53 PM, Robert Widmann <rwidmann at apple.com> wrote:
>>>>
>>>> Renaming is out of scope for this proposal, that’s why.
>>>>
>>>> On Jul 20, 2016, at 1:26 PM, Brandon Knope <bknope at me.com> wrote:
>>>>
>>>> I prefer this 100x more
>>>>
>>>> Is there any reason why this wouldn't work?
>>>>
>>>> Brandon
>>>>
>>>> On Jul 20, 2016, at 4:13 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>>
>>>> Yeah, I'd be happy to lose the parentheses as well.
>>>>
>>>> In the last thread, my take on simplifying the proposed syntax was:
>>>>
>>>> ```
>>>> import Swift using String, Int
>>>>
>>>> // or, for hiding:
>>>> import Swift using Int as _
>>>> ```
>>>>
>>>> The key simplification here is that hiding doesn't need its own
>>>> contextual keyboard, especially if we support renaming (a huge plus in my
>>>> book), as renaming to anything unused (or explicitly to `_`) is what hiding
>>>> is all about.
>>>> On Wed, Jul 20, 2016 at 15:01 Brandon Knope <bknope at me.com> wrote:
>>>>
>>>>>
>>>>>
>>>>> On Jul 20, 2016, at 3:08 PM, Xiaodi Wu via swift-evolution <
>>>>> swift-evolution at swift.org> wrote:
>>>>>
>>>>> As Joe and others mentioned in the previous thread, this syntax could
>>>>> be greatly simplified in ways that resemble analogous facilities in other
>>>>> languages. In particular I think it's alarmingly asymmetrical that, in your
>>>>> proposal, `import Swift using (String)` imports *only* String while `import
>>>>> Swift hiding (String)` imports *everything but* String. This becomes
>>>>> evident when chained together:
>>>>>
>>>>> ```
>>>>> import Swift using (String, Int)
>>>>> // imports only String and Int
>>>>> import Swift using (String, Int) hiding (String)
>>>>> // imports only Int
>>>>> import Swift hiding (String, Int)
>>>>> // imports everything except String and Int
>>>>> import Swift hiding (String, Int) using (String)
>>>>> // imports *nothing*? nothing except String? everything except Int?
>>>>> confusing.
>>>>> ```
>>>>>
>>>>> By contrast, Joe's proposed syntax (with some riffs) produces
>>>>> something much more terse *and* much more clear:
>>>>>
>>>>> ```
>>>>> import Swift.*
>>>>> import Swift.(Int as MyInt, *)
>>>>> import Swift.(Int as _, *)
>>>>> ```
>>>>>
>>>>>
>>>>> I really don't find this much clearer than the proposed one. The
>>>>> proposal reads much clearer.
>>>>>
>>>>> Joe's syntax has a lot going on in my opinion.
>>>>>
>>>>> For the proposal, do we really need the parentheses? It makes the
>>>>> syntax look heavier
>>>>>
>>>>> Brandon
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Wed, Jul 20, 2016 at 1:52 PM, Robert Widmann via swift-evolution <
>>>>> swift-evolution at swift.org> wrote:
>>>>>
>>>>>> Hello all,
>>>>>>
>>>>>> I’d like to thank the members of the community that have guided the
>>>>>> revisions of this proposal.  We have decided to heed the advice of the
>>>>>> community and break down our original proposal on modules and qualified
>>>>>> imports into source-breaking (qualified imports) and additive (modules)
>>>>>> proposals.  As qualified imports is the change most suited to Swift 3, we
>>>>>> are pushing that proposal now as our final draft.
>>>>>>
>>>>>> It can be had inline with this email, on Github
>>>>>> <https://github.com/apple/swift-evolution/pull/440>, or as a gist
>>>>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6>.
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> ~Robert Widmann
>>>>>>
>>>>>> Qualified Imports Revisited
>>>>>>
>>>>>>    - Proposal: SE-NNNN
>>>>>>    <https://gist.github.com/CodaFi/NNNN-first-class-qualified-imports.md>
>>>>>>    - Authors: Robert Widmann <https://github.com/codafi>, 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.
>>>>>>
>>>>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#motivation>
>>>>>> Motivation
>>>>>>
>>>>>> The existing syntax for qualified imports from modules is needlessly
>>>>>> explicit, does not compose, and has a default semantics that dilutes the
>>>>>> intended meaning of the very operation itself. Today, a qualified import
>>>>>> looks something like this
>>>>>>
>>>>>> import class Foundation.Date
>>>>>>
>>>>>> This means that clients of Foundation that wish to see only Date must
>>>>>> know the exact kind of declaration that identifier is. In addition, though
>>>>>> this import specifies exactly one class be imported from Foundation, the
>>>>>> actual semantics mean Swift will recursively open all of Foundation's
>>>>>> submodules so you can see, and use, every other identifier anyway - and
>>>>>> they are not filtered from code completion. Qualified imports deserve to be
>>>>>> first-class in Swift, and that is what we intend to make them with this
>>>>>> proposal.
>>>>>>
>>>>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#proposed-solution>Proposed
>>>>>> solution
>>>>>>
>>>>>> The grammar and semantics of qualified imports will change completely
>>>>>> with the addition of *import qualifiers* and *import directives*. We
>>>>>> also introduce two new contextual keywords: using and hiding, 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
>>>>>>
>>>>>> import-decl -> import <import-path> <(opt) import-directive-list>
>>>>>> import-path -> <identifier>
>>>>>>             -> <identifier>.<identifier>
>>>>>> import-directive-list -> <import-directive>
>>>>>>                       -> <import-directive> <import-directive-list>
>>>>>> import-directive -> using (<identifier>, ...)
>>>>>>                  -> hiding (<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 2 operations:
>>>>>>
>>>>>> 1) *using*: The *using* directive is followed by a list of
>>>>>> identifiers for non-member nominal declarations within the imported module
>>>>>> that should be exposed to this file.
>>>>>>
>>>>>> // The only visible parts of Foundation in this file are // Foundation.Date, Foundation.DateFormatter, and Foundation.DateComponents//// Previously, this was// import class Foundation.Date// import class Foundation.DateFormatter// import class Foundation.DateComponentsimport Foundation using (Date, DateFormatter, DateComponents)
>>>>>>
>>>>>> 2) *hiding*: The hiding directive is followed by a list of
>>>>>> identifiers for non-member nominal declarations within the imported module
>>>>>> that should be hidden from this file.
>>>>>>
>>>>>> // Imports all of Foundation except `Date`import Foundation hiding (Date)
>>>>>>
>>>>>> As today, all hidden identifiers do not hide the type, they merely
>>>>>> hide that type’s members and its declaration. For example, this means
>>>>>> values of hidden types are still allowed. Unlike the existing
>>>>>> implementation, using their members is forbidden.
>>>>>>
>>>>>> // Imports `DateFormatter` but the declaration of `Date` is hidden.import Foundation using (DateFormatter)
>>>>>> var d = DateFormatter().date(from: "...") // Validvar dt : Date = DateFormatter().date(from: "...") // Invalid: Cannot use name of hidden type.
>>>>>> d.addTimeInterval(5.0) // Invalid: Cannot use members of hidden type.
>>>>>>
>>>>>> Import directives chain to one another and can be used to create a
>>>>>> fine-grained module import:
>>>>>>
>>>>>> // This imports Swift.Int, Swift.Double, and Swift.String but hides Swift.String.UTF8Viewimport Swift using (String, Int, Double)
>>>>>>              hiding (String.UTF8View)
>>>>>>
>>>>>> Directive chaining occurs left-to-right:
>>>>>>
>>>>>> // 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.import Swift using (Int) hiding (String)// 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)
>>>>>>
>>>>>> Because import directives are file-local, they will never be exported
>>>>>> along with the module that declares them.
>>>>>>
>>>>>> <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 and should be removed or migrated.
>>>>>>
>>>>>> <https://gist.github.com/CodaFi/42e5e5e94d857547abc381d9a9d0afd6#alternatives-considered>Alternatives
>>>>>> considered
>>>>>> A previous iteration of this proposal introduced an operation to
>>>>>> allow the renaming of identifiers, especially members. The original intent
>>>>>> was to allow file-local modifications of APIs consumers felt needed to
>>>>>> conform to their specific coding style. On review, we felt the feature was
>>>>>> not as significant as to warrant inclusion and was ripe for abuse in large
>>>>>> projects.
>>>>>>
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> swift-evolution at swift.org
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>
>>>>>>
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution at swift.org
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>
>>>>>
>>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
> _______________________________________________
> 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/20160720/2da3dcc8/attachment.html>


More information about the swift-evolution mailing list