>> Actually, I can think of one very interesting boundary that roughly 
>> parallels the SPI/API boundary: the boundary between resilience domains. In 
>> other words, "public within resilience domain" may be a useful access level.
> 
> Hm. That may indeed be useful because it allows the compiler to omit 
> resilient information about the declaration. I'm worried that's just adding 
> more knobs that won't really be a benefit in practice, though.

I think it would be a benefit because it could be used to model the distinction 
between SPI and API and to omit SPIs entirely from the released swiftmodule, as 
you suggested Apple (and perhaps others) would need. It'd be nice to have that 
as a formal part of the language, natively supported by all the tools.

>> Mostly, it just bothers me that we have these two middle access levels 
>> (`moduleprivate` and `fileprivate`) which seem closely related compared to 
>> new-`private`, yet are both completely ad-hoc and elude decent naming. 
>> Calling them, say, `internal` and having `internal(#file)` be a special case 
>> of `internal(file names here)` seems like a nice way to rationalize them.
> 
> Can you elaborate on why "moduleprivate" and "fileprivate" are closely 
> related for you? To me all three of the proposed non-public levels are 
> "concentric circles"; one of them is bounded by braces, one by the 
> filesystem, and one by the files in your target (as described by Xcode or the 
> package manager or an ad hoc build).

I guess the way I see it is this:

Consider the inside of a function body. The things in it are lexically scoped: 
they are visible within the scope, including in nested scopes, but not outside 
it. Inner blocks can access the variables of outer blocks, but not vice versa. 
Because a function body is built from anonymous stack frames, it cannot really 
be made more globally visible, so we don't need to explicitly ask for this 
behavior.

Named module-wide entities, on the other hand, *are* nailed down to a stable 
location, so they *can* be made more globally visible. Thus, we do need access 
control keywords.

In my view, `private` is basically asking for the same behavior seen elsewhere 
in the language: lexically scoped access. The others—`fileprivate`, 
`moduleprivate`, and `public`—are asking for that behavior to be varied by 
exposing the symbol they're decorating more widely than normal.

Now, there is a very important distinction between `public` and the others. A 
public symbol is exposed to the world; at compile time, it is impossible to 
know what will use it. `public` represents a veil of ignorance for the 
optimizer.

But between these two natural boundaries—the complete visibility and ignorance 
of `public` and the strict, natural lexical scope of `private`—any access 
levels we introduce are artificial. Especially now that we have WMO, 
`fileprivate` is just `moduleprivate` with an artificial visibility limit. That 
limit could just as easily be to an enumerated list of files, to direct 
ancestor scopes (and their non-type child scopes), to extensions, to 
subclasses, to particular symbols, or to odd-numbered lines. We choose "the 
current file" because that happens to frequently be useful, but there's nothing 
magical about the current file that makes it especially appropriate.

I guess that's why I keep wanting to unify `fileprivate` and `moduleprivate` 
somehow: because I see `fileprivate` as an artificial limitation of 
`moduleprivate`, and it seems to me that other such limitations would be 
equally valid.

* * *

While working that out, I also came up with a new suggestion for keywording if 
we keep just these four levels and don't generalize `fileprivate` into an 
"internal, with limitations" mechanism:

* public
* moduleinternal
* internal
* private

This version saddles only the module access level, which rarely needs to be 
typed explicitly, with an awkward compound keyword. The file access level 
(which I suspect is more often necessary than many in this thread believe) gets 
a single, simple keyword. Additionally, by having only one gobbledygook access 
level, when you *do* see the gobbledygook keyword you don't have to try to 
parse it.

This does have the disadvantage of not matching C#'s meaning of `internal`; we 
could do something else, like `shared`/`moduleshared`, instead. But I'm not 
sure how valuable that correspondence is.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to