Swift protocol with "where Self" clause - swift

In addition to this syntax with a protocol extension:
protocol P {}
extension P where Self : UIView {}
... I discovered by accident that you can use the same where clause on the protocol itself:
protocol P where Self : UIView {}
Notice that this is not the same as a where clause constraining a generic protocol, and does not itself make P a generic protocol.
My experiments seem to show that only a colon can be used here, and the thing after the colon must be a class or a protocol (which may be generic).
I became curious: how did this escape my notice? So I went hunting for evidence of when it arose. In Swift 3.0, the former syntax is legal but not the latter. In Swift 3.3, both are legal. So the latter syntax must have been quietly introduced in something like Swift 3.2. I say "quietly" because I can't find anything about it in the release notes.
What is the second syntax for? Is it, as it appears, just a convenient way of making sure no other type can adopt this protocol? The Swift headers do not seem to make any use of it.

The ability to put superclass constraints on protocols declarations (that is, being able to define protocol P where Self : C where C is the type of a class) was a premature consequence of SE-0156, and the syntax should have been rejected in Swift 4.x until the feature was implemented. Attempting to use this feature in Swift 4.x can cause miscompilation and crashes, so I would avoid using it until Swift 5.
In Swift 5 (Xcode 10.2) the feature has now been implemented. From the release notes:
Protocols can now constrain their conforming types to those that
subclass a given class. Two equivalent forms are supported:
protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ }
Swift 4.2 accepted the second form, but it wasn’t fully implemented
and could sometimes crash at compile time or runtime. (SR-5581)
(38077232)
This syntax places a superclass constraint on MyView which restricts conforming types to those inheriting from (or being) UIView. In addition, the usage of MyView is semantically equivalent to a class existential (e.g UIView & MyView) in that you can access both members of the class and requirements of the protocol on the value.
For example, expanding upon the release notes' example:
protocol MyView : UIView {
var foo: Int { get }
}
class C : MyView {} // error: 'P' requires that 'C' inherit from 'UIView'
class CustomView : UIView, MyView {
var foo: Int = 0
}
// ...
let myView: MyView = CustomView(frame: .zero)
// We can access both `UIView` members on a `MyView` value
print(myView.backgroundColor as Any)
// ... and `MyView` members as usual.
print(myView.foo)

Related

Swift constrained protocol? [duplicate]

In addition to this syntax with a protocol extension:
protocol P {}
extension P where Self : UIView {}
... I discovered by accident that you can use the same where clause on the protocol itself:
protocol P where Self : UIView {}
Notice that this is not the same as a where clause constraining a generic protocol, and does not itself make P a generic protocol.
My experiments seem to show that only a colon can be used here, and the thing after the colon must be a class or a protocol (which may be generic).
I became curious: how did this escape my notice? So I went hunting for evidence of when it arose. In Swift 3.0, the former syntax is legal but not the latter. In Swift 3.3, both are legal. So the latter syntax must have been quietly introduced in something like Swift 3.2. I say "quietly" because I can't find anything about it in the release notes.
What is the second syntax for? Is it, as it appears, just a convenient way of making sure no other type can adopt this protocol? The Swift headers do not seem to make any use of it.
The ability to put superclass constraints on protocols declarations (that is, being able to define protocol P where Self : C where C is the type of a class) was a premature consequence of SE-0156, and the syntax should have been rejected in Swift 4.x until the feature was implemented. Attempting to use this feature in Swift 4.x can cause miscompilation and crashes, so I would avoid using it until Swift 5.
In Swift 5 (Xcode 10.2) the feature has now been implemented. From the release notes:
Protocols can now constrain their conforming types to those that
subclass a given class. Two equivalent forms are supported:
protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ }
Swift 4.2 accepted the second form, but it wasn’t fully implemented
and could sometimes crash at compile time or runtime. (SR-5581)
(38077232)
This syntax places a superclass constraint on MyView which restricts conforming types to those inheriting from (or being) UIView. In addition, the usage of MyView is semantically equivalent to a class existential (e.g UIView & MyView) in that you can access both members of the class and requirements of the protocol on the value.
For example, expanding upon the release notes' example:
protocol MyView : UIView {
var foo: Int { get }
}
class C : MyView {} // error: 'P' requires that 'C' inherit from 'UIView'
class CustomView : UIView, MyView {
var foo: Int = 0
}
// ...
let myView: MyView = CustomView(frame: .zero)
// We can access both `UIView` members on a `MyView` value
print(myView.backgroundColor as Any)
// ... and `MyView` members as usual.
print(myView.foo)

Swift: Is it possible to add a protocol extension to a protocol?

Lets say I have two protocols:
protocol TheirPcol {}
protocol MyPcol {
func extraFunc()
}
What I want to do is to create a protocol extension for 'TheirPcol' which lets extraFunc() work on anything which conforms to 'TheirPcol'. So something like this:
extension TheirPcol : MyPcol { // Error 'Extension of protocol 'TheirPcol' cannot have an inheritance clause.
func extraFunc() { /* do magic */}
}
struct TheirStruct:TheirPcol {}
let inst = TheirStruct()
inst.extraFunc()
The kicker in this is that 'TheirPcol', 'TheirStruct' are all handled by an external API which I do not control. So I'm passed the instance 'inst'.
Can this be done? Or am I going to have to do something like this:
struct TheirStruct:TheirPcol {}
let inst = TheirStruct() as! MyPcol
inst.extraFunc()
It seems there are two use-cases of why you may want to do what you are doing. In the first use-case, Swift will allow you to do what you want, but not very cleanly in the second use-case. I'm guessing you fall into the second category, but I'll go through both.
Extending the functionality of TheirPcol
One reason why you might want to do this is simply to give extra functionality to TheirPcol. Just like the compiler error says, you cannot extend Swift protocols to conform to other protocols. However, you can simply extend TheirPcol.
extension TheirPcol {
func extraFunc() { /* do magic */ }
}
Here, you are giving all objects that conform to TheirPcol the method extraFunc() and giving it a default implementation. This accomplishes the task of extending functionality for the objects conforming to TheirPcol, and if you want it to apply to your own objects as well then you could conform your objects to TheirPcol. In many situations, however, you want to keep MyPcol as your primary protocol and just treat TheirPcol as conforming to MyPcol. Unfortunately, Swift does not currently support protocol extensions declaring conformance to other protocols.
Using TheirPcol objects as if they were MyPcol
In the use case (most likely your use case) where you really do need the separate existence of MyPcol, then as far as I am aware there is no clean way to do what you want yet. Here's a few working but non-ideal solutions:
Wrapper around TheirPcol
One potentially messy approach would be to have a struct or class like the following:
struct TheirPcolWrapper<T: TheirPcol>: MyPcol {
var object: T
func extraFunc() { /* Do magic using object */ }
}
You could theoretically use this struct as an alternative to casting, as in your example, when you need to make an existing object instance conform to MyPcol. Or, if you have functions that accept MyPcol as a generic parameter, you could create equivalent functions that take in TheirPcol, then convert it to TheirPcolWrapper and send it off to the other function taking in MyPcol.
Another thing to note is if you are being passed an object of TheirPcol, then you won't be able to create a TheirPcolWrapper instance without first casting it down to an explicit type. This is due to some generics limitations of Swift. So, an object like this could be an alternative:
struct TheirPcolWrapper: MyPcol {
var object: MyPcol
func extraFunc() { /* Do magic using object */ }
}
This would mean you could create a TheirPcolWrapper instance without knowing the explicit type of the TheirPcol you are given.
For a large project, though, both of these could get messy really fast.
Extending individual objects using a child protocol
Yet another non-ideal solution is to extend each object that you know conforms to TheirPcol and that you know you wish to support. For example, suppose you know that ObjectA and ObjectB conform to TheirPcol. You could create a child protocol of MyPcol and then explicitly declare conformance for both objects, as below:
protocol BridgedToMyPcol: TheirPcol, MyPcol {}
extension BridgedToMyPcol {
func extraFunc() {
// Do magic here, given that the object is guaranteed to conform to TheirPcol
}
}
extension ObjectA: BridgedToMyPcol {}
extension ObjectB: BridgedToMyPcol {}
Unfortunately, this approach breaks down if there are a large number of objects that you wish to support, or if you cannot know ahead of time what the objects will be. It also becomes a problem when you don't know the explicit type of a TheirPcol you are given, although you can use type(of:) to get a metatype.
A note about Swift 4
You should check out Conditional conformances, a proposal accepted for inclusion in Swift 4. Specifically, this proposal outlines the ability to have the following extension:
extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}
While this is not quite what you are asking, at the bottom you'll find "Alternatives considered", which has a sub-section called "Extending protocols to conform to protocols", which is much more what you're trying to do. It provides the following example:
extension Collection: Equatable where Iterator.Element: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
// ...
}
}
Then states the following:
This protocol extension would make any Collection of Equatable elements Equatable, which is a powerful feature that could be put to good use. Introducing conditional conformances for protocol extensions would exacerbate the problem of overlapping conformances, because it would be unreasonable to say that the existence of the above protocol extension means that no type that conforms to Collection could declare its own conformance to Equatable, conditional or otherwise.
While I realize you're not asking for the ability to have conditional conformances, this is the closest thing I could find regarding discussion of protocols being extended to conform to other protocols.

Using NSHashTable to implement Observer pattern in Swift 3

Adding multiple delegates instead of only one is a quite common task. Suppose we have protocol and a class:
protocol ObserverProtocol
{
...
}
class BroadcasterClass
{
// Error: Type 'ObserverProtocol' does not conform to protocol 'AnyObject'
private var _observers = NSHashTable<ObserverProtocol>.weakObjects()
}
If we try to force ObserverProtocol to conform AnyObject protocol, we will get another error:
Using 'ObserverProtocol' as a concrete type conforming to protocol 'AnyObject' is not supported
Is it even possible to create a set of weak delegates in Swift 3.0?
Sure, it's possible.
AnyObject is the Swift equivalent of id in Objective C. To get your code to compile, you just need to add the #objc annotation to your protocol, to tell Swift that the protocol should be compatible with Objective C.
So:
#objc protocol ObserverProtocol {
}

Swift Extensions for Collections

I'm working on a framework to make it easier to work with Key Value Observing and I've defined a protocol for converting native Swift types to NSObject as follows:
public protocol NSObjectConvertible {
func toNSObject () -> NSObject
}
Extending the builtin types was easy, simply defining the function to convert the given type to the appropriate NSObject:
extension Int8: NSObjectConvertible {
public func toNSObject () -> NSObject {
return NSNumber(char: self)
}
}
When I got to the Array type, I hit a number of snags, which I tried to work out. I didn't want to extend any array type, but only arrays whose element type was itself NSObjectConvertible. And naturally, needed Array to itself conform to the protocol.
After hunting around on SO, it looks like extending the Array type itself is a little harder because it's generic, but extending SequenceType can be done. Except that I can't both constrain the element type and declare its conformance to the protocol in the same declaration.
The following:
extension SequenceType where Generator.Element == NSObjectConvertible : NSObjectConvertible = {
public func toNSObject () -> NSObject {
return self.map() { return $0.toNSObject() }
}
}
Produces a compiler error:
Expected '{' in extension
And the carat points to the ":" where I'm trying to declare the protocol conformance. Removing the protocol conformance compiles without errors, but obviously doesn't help the case.
I'm not sure if this is a bug, or if Swift simply can't (or doesn't want to) support what I'm trying to do. Even if I simply define the extension, then try to take care of the conformance in the body, it produces the risk of passing sequences that don't really conform to what they should.
At best it's a hacky solution to just fail in cases where a sequence with non-conforming members are passed. I'd much rather let the compiler prevent it from happening.
(This is in Swift 2.1, Xcode 7.1.1)
You can't add the protocol conformance, unfortunately.

Using Swift functions in Objective-C that have protocol-typed parameters

I have a Swift class called Helpers defined as follows:
class Helpers : NSObject {
class func sayValue(value:Printable) {
println(value)
}
}
I am trying to use this in an Objective-C .m file, like so:
[Helpers sayValue:#"Hello"];
But the compiler is complaining with the error: No known class method for selector 'sayValue:'
However if I change the sayValue to have a strict type, it works fine:
class Helpers : NSObject {
class func sayValue(value:String) {
println(value)
}
}
What's going on here?
You've already figured it out. Swift protocols don't map as types into Objective-C.
Always just ask yourself "Could I say this in Objective-C?" You can't say this in Objective-C:
+ (void) sayValue: (Printable*) value { ... }
That's illegal, because Printable (a protocol) isn't a type. So your Swift function defined that way doesn't magically map upward into Objective-C, as it has nothing to map to. It is filtered out, and Objective-C never sees it.
What I'm finding is that all this works remarkably cleanly. I was afraid that a Swift class that uses any non-Objective-C features wouldn't map to an Objective-C class at all. But, on the contrary, you can use all the pure-Swift features you like, and they simply don't map up into Objective-C: they are cleanly filtered out, and those parts of your Swift class that do map into Objective-C work just fine from Objective-C. It's quite brilliant.
You are free to define a protocol that maps as a type for purposes of, say, defining a delegate. But to do that, you must expose the protocol using #objc. For example, from one of my apps:
#objc protocol ColorPickerDelegate {
func colorPicker (/*...*/)
}
class ColorPickerController : UIViewController {
weak var delegate: ColorPickerDelegate?
// ...
}
You can't talk that way unless the protocol is #objc. Now Objective-C understands the type of delegate to mean id<ColorPickerDelegate> and you're in business.
(So you could probably talk the way you're suggesting by defining an #objc protocol MyPrintable which does nothing but adopt Printable; I haven't tried it, however, so that's just a conjecture.)