[swift-evolution] [Proposal][Discussion] Qualified Imports
Xiaodi Wu
xiaodi.wu at gmail.com
Thu Jul 21 12:08:45 CDT 2016
On Thu, Jul 21, 2016 at 11:14 AM, Robert Widmann <devteam.codafi at gmail.com>
wrote:
>
>
> ~Robert Widmann
>
> 2016/07/21 8:23、Xiaodi Wu <xiaodi.wu at gmail.com> のメッセージ:
>
> On Thu, Jul 21, 2016 at 2:02 AM, Robert Widmann <rwidmann at apple.com>
> wrote:
>
>>
>> On Jul 20, 2016, at 11:56 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>> On Thu, Jul 21, 2016 at 1:40 AM, Robert Widmann <rwidmann at apple.com>
>> wrote:
>>
>>>
>>> On Jul 20, 2016, at 10:04 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>
>>> On Wed, Jul 20, 2016 at 10:33 PM, Robert Widmann <
>>> devteam.codafi at gmail.com> wrote:
>>>
>>>>
>>>>
>>>> ~Robert Widmann
>>>>
>>>> 2016/07/20 19:01、Xiaodi Wu via swift-evolution <
>>>> swift-evolution at swift.org> のメッセージ:
>>>>
>>>> On Wed, Jul 20, 2016 at 8:10 PM, Robert Widmann <rwidmann at apple.com>
>>>> wrote:
>>>>
>>>>>
>>>>> On Jul 20, 2016, at 5:47 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>>>
>>>>> On Wed, Jul 20, 2016 at 6:30 PM, Robert Widmann <rwidmann at apple.com>
>>>>> wrote:
>>>>>
>>>>>> “The Phase Distinction” is a semantic one, not one built into the
>>>>>> import system itself.
>>>>>>
>>>>>
>>>>>
>>>>> I understand. To rephrase my question: why introduce this semantic
>>>>> distinction to Swift?
>>>>>
>>>>>
>>>>> What I meant is that even the system I’m modeling this on makes a
>>>>>> distinction between import directives that actually expose identifiers to
>>>>>> modules and import directives that modify identifiers that are already in
>>>>>> scope.
>>>>>>
>>>>>
>>>>>
>>>>> This is, IMO, very complex. I appreciate enormously the conceptual
>>>>> simplicity of the current Swift approach which, for all of its
>>>>> deficiencies, has only one import directive that does what it says on the
>>>>> tin: it exposes identifiers. I'm not bothered if it gains the ability to
>>>>> expose identifiers differently from one file to the next without keywords
>>>>> firewalled from each other to preserve the notion of phases of import.
>>>>>
>>>>>
>>>>> We are *not* changing the unqualified Swift import system. Take a
>>>>> gander at the proposal again, or even the first draft. Swift has a
>>>>> particularly strange syntax for qualified imports that hasn’t received
>>>>> attention since it was first introduced 2 major versions ago. That thing
>>>>> allows quite a variety of senseless variants that can be both completely
>>>>> expressed by and subsumed by `using` and `hiding`.
>>>>>
>>>>
>>>>
>>>> My sense, which I think has been echoed by others, is that the proposed
>>>> solution is syntactically complex, and now that I understand that you're
>>>> thinking through a multi-phase concept, also conceptually multilayered. I'm
>>>> not arguing that the existing syntax for qualified imports doesn't need
>>>> changing, only that there is room for radical simplification of the
>>>> proposed solution IMO. As I re-read this proposal once more, it strikes me
>>>> that the motivating issues identified (needlessly specific, does not
>>>> compose, etc.) don't clearly argue for the specific direction proposed as
>>>> opposed to alternatives like Joe's.
>>>>
>>>>
>>>> Perhaps they need to reread the proposal. Syntactically complex how?
>>>> We're introducing two keywords and using tuple syntax. Our grammar changes
>>>> are laid bare and take up 7 lines. I think there might be a general air of
>>>> confusing semantics changes with syntax changes.
>>>>
>>>
>>>
>>> I can't speak for the general air, but putting on my disinterested
>>> reader hat, I can see why the confusion might arise--
>>>
>>> The Motivation section begins:
>>> "The existing syntax for qualified imports..."
>>>
>>> And the Proposed Solution begins:
>>> "The grammar and semantics of qualified imports..."
>>>
>>> But the Detailed Design begins:
>>> "Qualified import syntax will be revised..."
>>>
>>> It's neither here nor there in terms of the proposal content, but
>>> suffice it to say that if one strings together the topic sentences in your
>>> proposal, the overarching narrative to be gleaned here is: "The current
>>> syntax for qualified imports is no good; therefore, we revise the semantics
>>> of qualified imports by changing the syntax." Sure.
>>>
>>>
>>> Ne’er the twain shall meet.
>>>>>>
>>>>>
>>>>>
>>>>> Yes, you explained this concept very clearly as it applies to Agda.
>>>>> But I just don't see why we should care to have this distinction. Yet you
>>>>> are very adamant about it. What am I missing?
>>>>>
>>>>>
>>>>>
>>>>> We should care because that is precisely what the two operations *do*.
>>>>> `using` and `hiding` introduce things or remove things from scope which is
>>>>> a very different operation from taking something that is already in scope
>>>>> and giving it a new name.
>>>>>
>>>>
>>>>
>>>> Perhaps I'm not phrasing my question very cogently. Of course, if we
>>>> are to have `using`, `hiding`, and `renaming`, we must observe the
>>>> distinctions between them.
>>>>
>>>>
>>>>
>>>> If you don’t want to think of them as part of the same import process,
>>>>> think of them instead in terms of their Swift equivalents today.
>>>>>
>>>>> import Foundation using (Date) == import struct Foundation.Date
>>>>> import Foundation hiding (Date) == import Foundation; @unavailable(*,
>>>>> “…") typealias Date = Foundation.Date
>>>>> import Foundation using (TimeInterval) renaming (TimeInterval, to:
>>>>> Time) == import typealias Foundation.TimeInterval; typealias Time =
>>>>> Foundation.TimeInterval
>>>>>
>>>>> Notice how it takes two declarations to create a renaming? It is not
>>>>> simple to drop being explicit about which names are actually in scope and
>>>>> expect a renaming to just implicitly slip in a using declaration. Nor is
>>>>> it simple to imagine _ as some magical namespace that you can pack away
>>>>> unwanted definitions into. using and hiding are very physical things and
>>>>> the rules for their behavior should be obvious and unambiguous - the
>>>>> proposal contains some examples of valid and invalid declarations to help
>>>>> with that.
>>>>>
>>>>
>>>>
>>>> The examples worry me, in fact. That we might need to contemplate the
>>>> behavior of a statement such as `import Foo using () hiding () hiding ()
>>>> using () hiding ()` suggests it's perhaps a little over-engineered for the
>>>> purpose. Why allow chaining of `using` and `hiding` anyway? The only
>>>> example given is of a nested type, which suggests nesting would be the way
>>>> to go:
>>>>
>>>>
>>>> We allow chaining specifically to avoid that nesting behavior. Let's
>>>> break up that chained import line by line to see why
>>>>
>>>> import Swift using (String, Int, Double, Character)
>>>> hiding (String.UTF8View)
>>>>
>>>> import Swift // Scope contains {all identifiers in Swift}
>>>> using (String, Int, Double, Character) // Scope contains {String.*,
>>>> Int.*, Double.*, Character.*}
>>>> hiding (String.UTF8View) // Scope contains
>>>> {{String.* - String.UTF8View.*}, Int.*, Double.*, Character.*}
>>>>
>>>
>>>> We express the exact same example in a much more human-readable way.
>>>> You can read this out loud in plain English if you don't believe me:
>>>> "import everything in Swift that is in String, Int, Double, and Character
>>>> except String.UTF8View"
>>>>
>>>>
>>>
>>> I have to disagree with your reasoning here. Unless I'm mistaken, the
>>> readability we're most concerned with is that of the written text, not its
>>> spoken form.
>>>
>>> Nesting is an almost exclusively _visual_ way of organizing text and it
>>> adds real clarity on the page. Of course, if your litmus test for
>>> readability is literally trying to read it out loud, you would conclude
>>> that nesting is inferior. However, you'd make that same conclusion about so
>>> many other choices in Swift syntax (take, for instance, `:` instead of
>>> `extends` or `->` instead of `returns`). I conclude, on the other hand,
>>> that Swift is clearly not aiming to be AppleScript-like in this respect.
>>>
>>>
>>> I disagree. Standard Library Swift reads left to right in a very
>>> carefully chosen and consistent manner - it has been refined on this list
>>> and by the team quite a lot to get it that way. You seem to think I’m
>>> arguing verbosity is the end goal (AppleScript?): I’m not. Clarity is the
>>> goal. It is unambiguous what you mean when you say
>>>
>>> import Swift using (String, Int, Double) hiding (String.UTF8View)
>>>
>>
>> Is it ambiguous to say `import Swift using (String hiding (UTF8View),
>> Int, Double)`?
>>
>>
>> What happens when it is time to extend this proposal to members?
>>
>
>
> Short answer: don't.
>
> Long answer: I've been studying documentation for the Agda model on which
> you're basing this proposal. I like it a lot, and it doesn't have any of
> these issues we're discussing.
>
> First: there's the distinction in Agda between `import` and `open`. It's
> `open` that allows you to hide and "re-"name, and these operations only
> concern the short, unqualified names that are exposed, never changing
> what's imported. Thus, none of this is mutating the API. By contrast, I
> see Agda offers `as` for importing something as something else, just like
> what's has been suggested in this thread and the last. All of this--the
> distinction between import and open, the distinction between `import ...
> as` and what's essentially typealiasing--reflects very closely the
> semantics found in other languages which I was trying to describe to you
> (poorly) yesterday.
>
> I don't see any facility in Agda where qualified names for definitions can
> be vaporized post-hoc by `hiding`. [Yes, I know that technically you're not
> making anything disappear, etc.; but the point is that when I'm hiding
> frobnicate() from Foo the original Foo.frobnicate() is no longer in the way
> of whatever I want to do.] Can you give an example where this is permitted
> in any other language? Why would you want to be able to do this to
> individual members? As discussed in the previous thread, it seems a recipe
> for some really nasty stuff.
>
>
> That was renaming. That is out of scope for this proposal.
>
And correctly so, IMO. What I'm saying is, let's make renaming of members
out of scope for *Swift*.
>
> Second: Agda explicitly prohibits chaining `using` and `hiding`. In fact,
> one piece of documentation said that the reason for this prohibition was
> "obvious."
>
>
> Agda doesn't permit using and hiding to be chained because they have a
> proper module system that encourages hiding by nesting modules to any depth
> and qualified importing or hiding their contents. We have no such
> facility, and I don't anticipate its inclusion in Swift, so I recovered
> that same power here.
>
If recovering that same power does not absolutely necessitate a
source-breaking change, then this could be postponed until we have a full
discussion on modules and any alternatives. Put another way, I can see why
you might *want* chaining as a way of recovering more power, but the
source-breaking changes that need to be made by next week surely do not
require chaining.
>
> If we're to go down the road of taking inspiration from Agda, I think your
> proposal is missing some of the key things that make it work well. In that
> language, a sharp distinction is drawn between import and open, and we
> could do well to observe the same. I've always thought it problematic that
> `import Foundation` in Swift does both so that we're stuck with unqualified
> names for everything in Foundation. It would probably be too late to make
> that distinction past Swift 3.
>
>
> That is a function of a module system and relevant to the second
> proposal. As qualified imports today make no distinction between open and
> imported modules, we felt it wasn't necessary to include it here. We want
> this. We want it badly. But this isn't the right place to ask for it.
>
Fine. But let's roll chaining and hiding into the same future discussion.
It's inextricably linked to a more complex vision and seems out of place in
this proposal.
Moreover, I'd seriously reconsider for the future whether facilities to
> hide members are appropriate for import statements, and whether trying to
> accommodate such facilities now is worthwhile. And I'd consider why it is
> that Agda prohibits freeform chaining of using, hiding and renaming, and
> whether Swift needs it for anything. It is not ideal to have to explain
> what `hiding (String) using (String)` does; it shouldn't be possible to
> write such a thing.
>
>
> Then, as I've said before, we'll use diagnostics to make this case
> better. This is a case that is explicitly spelled out in the proposal. If
> it would remove this case, you could argue that directives may not refer to
> unqualified identifiers from earlier directives. That seems unnecessarily
> artificial just to remove something that has completely valid semantics.
>
>
>
> This syntax fits well with the overall direction of the language itself.
>>> For example, I use whitespace here out of habit but here’s nothing stopping
>>> you from making these look like the (meta)function invocations they really
>>> are
>>>
>>> import Swift
>>> using(String, Int, Double)
>>> hiding(String.UTF8View)
>>>
>>>
>>> In the comments you've used the nested notation `{{String.* -
>>> String.UTF8View.*}, Int.*, Double.*, Character.*}` to explain what it is
>>> your proposed syntax means. I really do find that, with all the punctuation
>>> in it, clearer than the chained notation. Of course, written `(String
>>> hiding UTF8View), Int, Double, Character`, it would be clearer still.
>>>
>>> Critically, it eliminates the possibility of absurd chains of `hiding ()
>>> using () hiding () using ()`, which create many more ways to represent the
>>> same subset of imports than can a nested syntax.
>>>
>>>
>>>
>>> If you wish to express this, why should the language stop you?
>>>
>>
>> Given two options for syntax, one where expressing this chain is never
>> necessary or even possible, and another where it is possible and perhaps
>> even necessary, the former wins in terms of clarity, no?
>>
>>
>> Yours does not exclude this possibility, it merely shuffles it around
>> (unless you plan on banning the empty tuple. In which case, why?)
>>
>
> The first part answers the second :)
> I wouldn't use tuples at all. Moreover, since you seem to be requiring
> parentheses around single elements, you're not even really using tuples
> here, but rather argument lists. As Brandon mentioned above, I don't see
> the need to try to use either tuples or argument lists:
>
> ```
> import Swift using String, Int, Double
> import Swift using (String hiding UTF8View), Int, Double
> ```
>
>
>> import Swift using (String using(UTF8View hiding ()), Int hiding (),
>> Double hiding())
>>
>> At this point we’re just circling around an edge case described in the
>> proposal as ripe for a merge-by-diagnostic.
>>
>
> The point I'm making is that chaining is inelegant in general, the edge
> case being only an extreme example of where it goes off the rails. In other
> words, the edge case is an argument ad absurdum for a larger issue. Of
> course, the edge case itself can be flagged by a diagnostic. There
> shouldn't have to be a need for it.
>
> Or better yet: we can offer diagnostics about this case just as we can
>>> offer diagnostics for doubled imports or improperly nested imports. A big
>>> part of why this proposal exists is because the existing diagnostics around
>>> qualified imports are uninformative and unhelpful.
>>>
>>> Now reread the chaining example in the proposal.
>>>>
>>>>
>>>> ```
>>>> import Swift using (String hiding (UTF8View), Int, Double)
>>>> ```
>>>>
>>>>
>>>>
>>>>> A qualified import is defining a procedure to import a subset of
>>>>>> identifiers. That’s it.
>>>>>>
>>>>>
>>>>>
>>>>> Right, and I think an entirely different way of thinking about this
>>>>> would be much easier to learn and teach. Whether using, hiding, and
>>>>> renaming are to be supported now, later, or never, my mental picture of how
>>>>> it fits together is quite simple:
>>>>>
>>>>> Analogy--suppose I am a pickle merchant. I import Foo-branded pickles
>>>>> from vendor X. I must re-label them with the right nutritional information
>>>>> before I can sell in this country. I can have labels printed saying that
>>>>> they are Foo-branded pickles. I can have them branded as Bar-branded
>>>>> pickles. Or I can have the labels deliberately misprinted, and then these
>>>>> pickles will never see the light of day. Point is, each of these is an
>>>>> active choice; even if I sell these as Bar-branded pickles, it's not that
>>>>> these pickles reached the domestic market as Foo-branded pickles, after
>>>>> which I scratched out the label with a Sharpie. These pickles had no
>>>>> domestic brand until I gave it one.
>>>>>
>>>>> Back to importing modifiers--I import type Foo from module X. In my
>>>>> code, I need to make a choice to call this type Foo, or Bar, or nothing at
>>>>> all. In other words, there is only one directive, importing, and I am
>>>>> importing `Foo as Foo`, `Foo as Bar`, or `Foo as _`. Meanwhile, `import X
>>>>> using Foo` or `import X.Foo` (whatever the color of the bikeshed) would
>>>>> just be a shorthand for `import X using Foo as Foo` or `import X.Foo as
>>>>> Foo`. In this conceptualization, if I choose to import Foo as Bar, it's not
>>>>> that I'm importing Foo into the scope, then changing the identifier to Bar.
>>>>> The only identifier it ever has in this scope is Bar.
>>>>>
>>>>>
>>>>> And I’m the one with the complex semantics? :)
>>>>>
>>>>
>>>>
>>>> I'm just trying to put into words what I'm familiar with after working
>>>> in other languages such as Python.
>>>>
>>>>
>>>> Python may not be the right mindset for this. Their import story is
>>>> much simpler because of their module system and generally simpler
>>>> programming model.
>>>>
>>>>
>>>>
>>>> How about this:
>>>>>
>>>>> Using and Hiding relate to each other the way && and || do for bools.
>>>>> If && can be said to “prefer to return false, but return true given no
>>>>> other alternative” and || can be said to “prefer returning true, but return
>>>>> false given no other alternative”, then hiding can be said to “prefer
>>>>> importing all identifiers unless told not to in specific instances” and
>>>>> using can be said to “prefer importing no identifiers unless told to in
>>>>> specific instances”.
>>>>>
>>>>> import Module.Name using (A, B, C, …) === import Module.Name hiding
>>>>> (ALL_NAMES - {A, B, C, ...})
>>>>> import Module.Name hiding (A, B, C, …) === import Module.Name using
>>>>> (ALL_NAMES - {A, B, C, ...})
>>>>>
>>>>> That seems a particularly simple explanation to me. Let me know if
>>>>> anything else is unclear.
>>>>>
>>>>
>>>>
>>>> Your mental framework is clear. It's one that's just not found in very
>>>> many other languages. Many of these have import declarations (or similar)
>>>> with simpler syntax, yet they seem to address at least some of the problems
>>>> that motivate your proposal. I guess my question in the end is, why have
>>>> you chosen Agda as the basis for qualified imports in Swift and not one of
>>>> these other languages?
>>>>
>>>>
>>>> I chose Agda because it's the only major language I could find that
>>>> treated identifiers like notation and used its module system for *real*
>>>> organization of code; it's just a name, it can change if you want it
>>>> to. The entire language is flexible. You can redefine functions with just
>>>> an =, you can give new syntactic transformations without having to write
>>>> crazy macros or worrying about hygiene. You get so much support from the
>>>> type system too that all of these features just work together and you can
>>>> sit back and feel satisfied that your tools pushed you to write *good
>>>> code. *I wrote it with Agda in mind because they took the time to
>>>> think about the interactions between modules, code, and scope in a way we
>>>> just haven't had the time to yet.
>>>>
>>>> Many of these imports have simpler syntax but don't chain so lose
>>>> expressiveness (Java). Or may have simpler surface syntax but don't
>>>> properly interact with a moduleless system (Python, Java). Or may have a
>>>> simpler syntax and give way to ambiguities (Python) when used in Swift.
>>>> Agda is unambiguous, scalable, extensible, and simple.
>>>>
>>>> Please don't confuse what's new with what's complex. But at the same
>>>> time if there are any unexplainable loopholes we should know about them. I
>>>> just haven't heard much I couldn't point to the proposal about yet so I
>>>> don't see a reason to change.
>>>>
>>>>
>>>
>>> Thanks for this insight. It's clear that you're aiming at a far richer
>>> system in the future. However, it's hard to gauge how far Swift will
>>> eventually scale/extend what you're proposing here. I don't think there's
>>> any denying that the solution you've chosen introduces more involved
>>> semantics and a more verbose syntax than what's strictly necessary to
>>> address the specific motivating problem you give in this particular
>>> instance. Without a better sense of the outer bounds of how far this system
>>> will eventually be pushed, it's hard to judge whether the eventual payoff
>>> will be "worth it." And without any mention of the grander plan, I suspect
>>> the feedback you're going to get will continue along the path of trying to
>>> tear away whatever you're trying to put in place for the future which is
>>> not discernibly necessary for solving the immediate problem at hand.
>>>
>>>
>>> If you believe this proposal is not extensible then cite a particular
>>> example, otherwise I can only say that I can’t tell the future. The syntax
>>> presented here is inspired by a tiny, tiny fragment of a language with an
>>> incredibly rich import mechanism and module system. It’s unclear how much
>>> of that system fits with Swift current - we already tried to formalize
>>> quite a bit in the first draft. For right now, *this* proposal is
>>> trying to clean up a long-neglected part of the language. If you feel that
>>> we’ve failed in that regard then tell me. Otherwise I’m fine with my
>>> syntax being pulled in a different direction in future additive proposals.
>>> I just want to fix this part of the language before the window on
>>> source-breaking changes closes for a while.
>>>
>>>
>>>
>>>>
>>>>
>>>>>
>>>>>
>>>>> On Jul 20, 2016, at 4:17 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>>>>
>>>>>> 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
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>> _______________________________________________
>>>> 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/71e9e172/attachment.html>
More information about the swift-evolution
mailing list