I would feel better if we force the use of fileprivate over private when it’s actually available in the file’s scope. Cases like private extension reuses private keyword but provides fileprivate semantics instead, introducing unnecessary confusion and styling issues.
I’m personally satisfied with fileprivate (or private(file) as someone proposed), and I believe making the semantics clear at first glance is more important than eliminating keywords.
Related, I would love to see exhaustivity checking possible for structs. I tend to prefer structs over enums for almost everything, but it would be nice if I could tell the compiler somehow that this is an "exhaustive" struct. Perhaps using CaseIterable or something?
public struct ServerEnvironment: Equatable, CaseIterable {
public static let allCases = [.production, .qa, .dev]
public static let production = ServerEnvironment(host: "production.example.com", name: "Production", ...)
public static let qa = ServerEnvironment(host: "qa.example.com", name: "QA", ...)
public static let dev = ServerEnvironment(host: "dev.example.com", name: "Development", ...)
private init( ... ) { }
}
// elsewhere:
let environment: ServerEnvironment = ...
switch environment {
case .production: // do something only for Production
case .qa: // do something only for QA
case .dev: // do something only for Development
}
The "exhaustive" bit is that I would not need a default case because I have handled every possible case as defined by the CaseIterable conformance. It is not possible for the user of ServerEnvironment to get anything except one of those three values.
Maybe this will be possible if we get something like @const and then the compiler could infer that from a @const allCases or something along the lines.
public struct ConformanceLimiter {
fileprivate init() {}
}
public protocol ClosedProtocol {
var conformanceLimiter: ConformanceLimiter { get } // can not be constructed outside of the library
}
Yeah, I've done this before with an associated type to prevent "copying" a conformance limiter from one conformer to another:
public protocol MyClosedProtocol {
static var closer: Closer<Self> { get }
// regular requirements...
}
public struct Closer<T> {
// publicly visible, but only internally constructible
// generic type prevents using a Closer<T> on different conformers of "MyClosedProtocol"
internal init() { }
}