New Access Modifier: package

that’s understandable. how do we feel about reconciling this idea with the existing @_spi feature, maybe with something like:

@_spi(package)
@_spi(external)
@_spi(packageprivate)

then imports of package-local modules would always be implicitly @_spi(package) imports.

1 Like

To summarize the assumptions we could make for those modules in the same package, does the following list sound reasonable:

  1. Modules in the same package belong to the same organization
  2. Modules in the same package are always compiled together so we could reasonably expand the resilient scope from a single module to the entire package
  3. Package is of a reasonable size so that the impact of changes to the package-level APIs could be easily known by the authors

some others?

1 Like

The package modifier does behave a lot like a special case of the @_spi attribute, so I think it's reasonable to wonder about the relationship between the features. One way to approximate the functionality of this modifier today would be to write the package decls as @_spi(Package) public func foo() { ... } and then in all of the modules in your package prepend @_spi(Package) to every import <Foo>. However, @_spi is really meant to be a tool for curating the external interface of a module for consumption by separate levels of external audiences. In the live at head environments I described earlier, @_spi decls have the same source stability requirements as standard public decls; it's just a bit easier to track down and coordinate with the users of @_spi.

To illustrate why I think package and @_spi serve different purposes I'll again make an analogy with Obj-C/C framework headers:

Swift modifier Obj-C/C header visibility Intended audience
public Public all modules
@_spi(...) public Private authorized external modules
package Project modules in the same project

I think that each of these distinct levels of visibility is important to have as a library owner and therefore I wouldn't want to see @_spi and package combined into a single feature. Could you establish a convention where @_spi(Package) declarations are understood to be only for use in the same package? Yes, but unless the tooling also understands the convention many of the potential benefits of the proposed feature are lost. If you want to be really sure no external parties are using your package interfaces, then the compiler should prevent use of @_spi(Package) decls outside the package. And something like "whole package optimization" is only possible if the compiler and other tools know which declarations are used outside of the package and which are not. Since the main benefits require that these declarations be treated differently than normal @_spi declarations, I think it's better to just have a distinct spelling that makes the difference clear.

2 Likes

I think there’s a stronger version of this argument: @_spi public declarations have the same binary stability requirements as normal public declarations. Since the whole package is built as a unit, package declarations can have unstable—and therefore more efficient—ABIs.

5 Likes

Link to the review of the proposal is at SE-0386: `package` access modifier

1 Like