Hello Swift community, I know I know, some of our souls are bleeding after the tiring mail-list discussions in dozens of similar threads, but I still feel that we have finally to sort this out. In the end we also moved to a forum not only for discoverability of older topics and better communication, but also to be able to push the language forward without necessarily relying on the help of the core team. In fact this is also implied by the new review rules where we must provide an implementation up front in order to get to a review process.
That said, I'd like to push this topic forward and hopefully find a group of people which share some interest in this topic and also implementors who are willing to tackle this for the next major release.
The topic was spread around different threads on the mailing list, that's why I wanted to start over, or better yet merge the discussion into one thread, so that the process is more organized.
Here are some of the threads I could find:
-
[Draft] A Consistent Foundation For Access Control: Scope-Bounded Capabilities
-
open/public protocol with not overridable default implementation in the future?
Yes this is another topic about two access modifiers, but only because access modifiers solves that issue nicely and in a consistent way. During the rush towards Swift 3 we introduced the open
access modifier and made public
the closed outside own module access modifier which is a great thing. However during the review only a very little of reviewers had some concerns that by introducing open
to classes will left protocols out of the game and create (a) an exclusive access modifier for classes and (b) and inconsistent public behavior.
IMHO we as developer should benefit from all sort of possible constraints that are provided by the language for us. If we can say that classes cannot be subclassed outside a module, but still extended, why cannot we say that protocols cannot be conformed outside our module. Furthermore closed protocols should still be extendable and even can be subtyped by the user, this will allow the user to retroactively conform our types with his/her own refinement of the protocols and still forbid the conformance in own project. This also means that such a closed but public protocol can only be used as an interface.
Then open protocol
will behave the same way as public protocol
behave today. This is a nice alignment to the open/public class
behavior.
A quick example:
// MODULE A
public protocol PublicProtoA {
func doWork()
}
open protocol OpenProtoA {
func beLazy()
}
open class Human : PublicProtoA {
...
}
// MODULE B
import ModuleA
protocol ProtoB : PublicProtoA {
func doMoreWork()
}
class Robot {}
extension : ProtoB { } // error cannot conform to ProtoB because `PublicProtoA` is public (closed)
extension : OpenProtoA { ... } // this is okay
extension Human : ProtoB { ... } // Retroactively conform a type to a refinement protocol
let lifeForm: Any = ...
if let human = lifeForm as? PublicProtoA {
// This is an allowed use as an interface through dynamic type casts
}
To not break anything in Swift 5 mode all current public
protocols will become open
and public
will have a closed behavior like described above.
This will also allow the core team to disallow the conformance to all hidden yet public protocols annotated with an underscore in the standard library.
Here is a list of such public protocols that I could find today:
_MinimalIterator
_HasCustomAnyHashableRepresentation
_ObjectiveCBridgeable
_ExpressibleByBuiltinIntegerLiteral
_ExpressibleByBuiltinFloatLiteral
_ExpressibleByBuiltinBooleanLiteral
_ExpressibleByBuiltinUnicodeScalarLiteral
_ExpressibleByBuiltinUTF16ExtendedGraphemeClusterLiteral
_ExpressibleByBuiltinExtendedGraphemeClusterLiteral
_ExpressibleByBuiltinStringLiteral
_ExpressibleByBuiltinUTF16StringLiteral
_ExpressibleByBuiltinConstStringLiteral
_ExpressibleByBuiltinConstUTF16StringLiteral
_ExpressibleByStringInterpolation
_ExpressibleByColorLiteral
_ExpressibleByImageLiteral
_ExpressibleByFileReferenceLiteral
_DestructorSafeContainer
_AppendKeyPath
_DefaultCustomPlaygroundQuickLookable
_SwiftNewtypeWrapper
_Pointer
_BitwiseOperations
_Mirror
_ShadowProtocol
_NSFastEnumeration
_NSEnumerator
_NSCopying
_NSArrayCore
_NSDictionaryCore
_NSDictionary
_NSSetCore
_NSSet
_NSNumber
_NSArrayCore
_NSDictionaryCore
_NSSetCore
_NSStringCore
_NSStringCore
_UnicodeEncoding
_UnicodeParser
_OpaqueString
_UTFParser
_AppKitKitNumericRawRepresentable
_AVCaptureDeviceFormatSupportedColorSpaces
_AVCapturePhotoOutputSwiftNativeTypes
_AVCapturePhotoSettingsSwiftNativeTypes
_CFObject
_CGColorInitTrampoline
_ObjectiveCBridgeableError
__BridgedNSError
_BridgedNSError
_BridgedStoredNSError
_ErrorCodeProtocol
_KeyValueCodingAndObserving
_INRideOptionMeteredFare
_UIKitNumericRawRepresentable
PS: I don't want this topic to escalate to a debate whether or not we should bring up this discussion or not. That said if you don't share any interest in that topic, please don't put a rock in it's possible way of success. ;)