Hi all,
The review of SE-0409: Access-level modifiers on import declarations concluded on September 26th.
The Language Steering group has decided to accept the proposal with a single modification. Namely, in addition to access level modifiers (internal, public, etc.), import declarations will be able to be marked with @usableFromInline to mark an imported module whose declarations should be available for use in the body of @inlinable functions, but still restricted from appearing in the public interface of the importing module. The Language Steering group agreed that it did not make sense to force users to abandon the interface-level checking provided by this proposal (by making the import a public import) just to use a declaration from an inlinable function body.
Overall reception of the feature was generally positive, at least as to the problem raised being worth solving. There were some questions raised as to whether the proposed solution was on the right track.
Some reviewers wondered whether it was appropriate for global property such as "is this module a public dependency or an implementation detail" to be inferred based on the upper bound of it's imported visibility across all source-file-local import declarations, and suggested that marking dependencies with this information in, say, the package manifest might be a better approach. While the Language Steering Group does not rule out the possibility of some sort of marking in the build system which could enforce "this module cannot be imported at higher than internal visibility," the Group felt that:
- The ultimate effect of different
importaccess levels was significant enough to warrant some sort of marking in the source file, so that users reading code can easily see which dependencies in the file are permitted to be used in the interface with the corresponding access level(s). - The problem being solved is sufficiently a language-level concern that it should not be only the responsibility of the build system to support/enforce dependency visibility—it should be a first-class language feature that Swift itself allows programmers to express regardless of the build system they are using.
Accepting that some source-level marker (attached to import declarations) was appropriate, the Language Steering Group considered the concerns about the potential unclarity of the public import Foo spelling. Some reviewers felt that this spelling incorrectly implied behavior more similar to @_exported than what was actually proposed. That is, reviewers expected that public import Foo would 're-export' the contents of the Foo module for use from the importing module's namespace. One reviewer noted that perhaps a more accurate, if more awkward, spelling would be @usableFromPublic, @usableFromInline, etc.
The Language Steering Group acknowledges that the public in public import Foo has a different meaning than the public in, say, public struct Bar. However, the Group elected to stick with the proposed spelling for the following reasons:
- The use of
public importin library code is likely to be relatively pervasive, and a more heavyweight, explicit spelling like@usableFromPublicor@usableFrom(public)or similar would quickly become too noisy. - The possible misinterpretation is relatively benign: users who expect
public import Footo re-export Foo's contents from their own module will quickly discover that this is not, in fact, its function, and then be able to correct their usage in whatever way they choose (e.g., by applying@_exported). - Even if we were to formalize
@_exportedas an official language feature, we would not want to use thepublic import Foospelling for such a specialized operation with such wide-reaching implications, and so using thepublic importspelling for the behavior proposed here does not 'close off' its use for different functionality in a way that is concerning.
There were some further questions and concerns raised about details of the proposal:
- Some felt that the inclusion of the
privateaccess level for import statements was unnecessarily fine-grained. The Language Steering group felt that the use case of a wrapper file around a library that an author does not want to accidentally 'leak' to the rest of the module was sufficiently justification forprivate import, and that the alternative of factoring that file out into a separate module was too burdensome to be a suitable solution. - Others noted that
privateandfileprivatewere redundant in this proposal becauseimportdeclarations can only appear at file scope, and suggested that the language should just pick one to be used withimportdeclarations and ban the other. The Language Steering group does not feel that an arbitrary restriction here is warranted, and thatimportdeclarations should be able to be marked as eitherprivateorfileprivatejust like any other top-level declaration.
Thank you for participation in the evolution process!
Frederick Kellison-Linn
Review Manager