In 2016 there was this great proposal: swift-evolution/NNNN-introduce-typeprivate-access-control-level.md at master · goncaloalvarez/swift-evolution · GitHub
The idea is to add "typeprivate" so you can put extensions into separate files to improve code readability without having to resort to "internal". (Currently any extensions that access private stored properties must all be in the file that declares the type, and "fileprivate" must be used. However this can lead to bloated code files.)
If the original "typeprivate" is seen as too "loose," here are two extra restrictions that would make "typeprivate" unable to be stealthily abused.
Extra Restriction 1: Typeprivate extends only to Explicit Extensions
To avoid any file in the module being able to get around typeprivate restrictions by simply using an extension, we could add some simple extra restrictions to be enforced by the compiler.
The first extra restriction would be a rule that only allows typeprivate access in files whose name starts with "NameOfParent+".
For example given "Foo.swift" with:
public struct Foo {
public typeprivate(set) var bar: Bar? = Bar()
}
Then the only way to have typeprivate access from outside this file would be to have a file like "Foo+Quxable.swift" {
extension Foo: Quxable {
func clearBar() {
bar = nil
}
}
That way, we can separate extensions out into separate files without having to make private things internal. But code files that aren't explicit extensions would not get typeprivate access.
Extra Restriction 2: Explicit Extensions that extend typeprivate may not do anything else
If that's not enough, then we could further restrict the first restriction by specifying the following additional rule.
For any type "Foo" that uses a typeprivate access level, any files "Foo+ExtensionName" may only contain extensions on Foo (but may not contain other top-level declarations).
That way, it would be impossible for another type to bypass the typeprivate level by sneaking code into explicit extension files. (They could only do it by putting an extension in the main file.)
My Recommendation
To me, the second restriction seems a bit much.
But I like the first restriction because it would let you still be able to have a CODEOWNERS file that covers any files with typeprivate access, because git lets you use wildcards :D
I think this would be a nice, additive, quality-of-life improvement that would encourage better code readability and more compact code files, without resorting to declaring things as internal just to do so.
This could be especially beneficial in allowing new capabilities for CoreData types, where you have an extension in a separate file to separate the auto-generated code away from the manual code. In such an arrangement you cannot have private properties accessed in the extension which is very annoying and makes CoreData less safe.
Thoughts?
My Responses to the Likely Counter-Arguments:
To those who might say, "what is wrong with long code files full of extensions," I would say if you are using extensions to keep code-generated files separate from manually written ones, using a single file is bad because the generator will overwrite your manually-written code. As well many people prefer several smaller files to one big one.
To those who might say, "We already have too many access-level specifiers," I would counter that no, we don't. Five is actually not very many of anything. Five is hardly even "several." It's basically just a handful. It's a single-digit quantity. And if six is really too many, then we could deprecate "fileprivate," or add the proposed file-naming rule above to slightly expand "fileprivate" (instead of using it to restrict "typeprivate"), because even that will not break anyone's code (since it's a purely additive change). Either way there would be nothing that could force you to use this new access level. You could simply pretend like it wasn't even there, or tell all your devs to never use it. Or maybe we could even have a compiler flag to disable whatever access levels you don't want to get used in your project.
To those who might say, "If you need to use something like typeprivate it means you are architecting your code poorly." To that I would counter, no, it just means I want to break up a really long code file into multiple files for the sake of readability. I hope you can give a better counter-argument.
That's not to say I think this is a perfect idea—maybe there is some reason why it couldn't work? But I really think (especially with the first extra restriction mentioned above) this would be very nice to have, and it also (to me) feels a lot more sensible than "fileprivate" (which seems to encourage the practice of adding a bunch of stuff to a single file).