~Robert Widmann

2016/07/21 1:43、Pyry Jahkola <[email protected]> のメッセージ:

> Back to the pre-proposal itself,
> 
> I support taking it forward and it being accepted in some form. However, I 
> remain unconvinced that we'd ever want `hiding` imports in Swift.
> 
> Here are a few specific comments on the text (8 in total):
>> 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.
>> 
> 
> 1. Given this motivation, isn't it sufficient being able to import without 
> knowing the exact kind of declaration? In other words, I agree we want 
> `using` imports, but what motivates `hiding` imports really?
> 
> As it was pointed out by Félix, the use of `hiding` imports moves away the 
> focus of what is imported into what is not imported, and while name conflict 
> problems usually arise when importing another module on top of already 
> working code, I think it's better to fix them at the import statement which 
> brings in the winning name declaration, i.e. the `using` import.
> 
> 
>> 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.
>> 
> 
> 2. Is there a typo above? The proposal does not mention import qualifiers 
> anywhere else. I guess those are part of what got postponed into later 
> proposals.
> 

It is.
> 
>> Detailed design
>> 
>> 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.DateComponents
>> import Foundation using (Date, DateFormatter, DateComponents)
> 3. I support the idea of `using` imports. That's something we do need, and 
> its introduction is sufficient to cover the existing use cases of the old 
> selective import syntax about to be deprecated here.
> 
> 
> 
>> 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.
>> 
> 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.  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.

> 
> 
> 
>> 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.UTF8View
>> import 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)
> 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?  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?  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.

> 
> 
>> Because import directives are file-local, they will never be exported along 
>> with the module that declares them.
>> 
> 6. +1 on imports being file-local, that's essentially what we have today.
> 
> 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.
 
> 
> 
> 7. (Off-topic to this proposal.) Given that you briefly expressed the 
> interest in turning imports `public` or `internal` — some of which would 
> indeed be useful in a better module system —, I think it's curious in that 
> design that the default visibility level of imports would likely be 
> `fileprivate`, which is different from the rest of Swift. That said, I think 
> it's absolutely right for imports to remain file-local by default, because 
> explicit tends to be better than implicit.
> 
> 
>> 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. 
>> 
> 8. +1 on deprecating the old selective import syntax.
> 
> Thank you for driving this forward!
> 
> — Pyry
> 
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to