How to add a protocol which contains associatedtype as a property in another protocol? [duplicate] - swift

I am trying to create a Dictionary (actually a HashSet) keyed on a custom protocol in Swift, but it is giving me the error in the title:
Protocol 'myProtocol' can only be used as a generic constraint because it has Self or associated type requirements
and I can't make heads nor tails of it.
protocol Observing: Hashable { }
var observers = HashSet<Observing>()

Protocol Observing inherits from protocol Hashable, which in turn inherits from protocol Equatable. Protocol Equatable has the following requirement:
func ==(lhs: Self, rhs: Self) -> Bool
And a protocol that contains Self somewhere inside it cannot be used anywhere except in a type constraint.
Here is a similar question.

To solve this you could use generics. Consider this example:
class GenericClass<T: Observing> {
var observers = HashSet<T>()
}

Related

For a generic class, where the generic type conforms to protocol X, how to create an instance of that class with a generic protocol

I want to create a class Game with a generic type which conforms to Equatable. Then I want to be able to use types, which are not by default equatable, like Shape.
If I create an instance with type String, everything works aas intended.
If I create an instance with type Shape, it fails, as expected, since Shape does not conform to Equatable.
My Idea is to use a protocol EquatableShape, which conforms to both Shape and Equatable. Then use it like that:
import SwiftUI
struct Game<Content> where Content: Equatable {
}
var stringGame: Game<String> // ok
var shapeGame: Game<Shape> // obviously fails, since Shapes are not Equatable
// error message: "error: MyPlayground.playground:8:16: error: type 'any Shape' does not conform to protocol 'Equatable'
// Define a protocol EquatableShape, which is Equatable
protocol EquatableShape: Shape & Equatable { }
// Optional: provide a default implementation
extension EquatableShape {
static func == (lhs: any EquatableShape, rhs: any EquatableShape) -> Bool {
return true // some logic here
}
}
// Now every instance which conforms to EquatableShape also conforms to Equatable
struct CircleES: EquatableShape {
func path(in rect: CGRect) -> Path {
return Circle().path(in: rect)
}
}
var circleESGame: Game<CircleES>
// Therefore the compiler should realise this
var equatableShapeGame: Game<EquatableShape> // <= Why does this fail?
// error message: "error: MyPlayground.playground:30:25: error: type 'any EquatableShape' cannot conform to 'Equatable'"
// <= Why does it say EquatableShape CANNOT perform to 'Equatable', while 'any Shape' DOES NOT conform to protocol 'Equatable'
// Workaround 1: Define a container, which stores the shape.
struct EquatableShapeContainer: Equatable {
static func == (lhs: EquatableShapeContainer, rhs: EquatableShapeContainer) -> Bool {
return true
}
let shape: any Shape
}
// This works, but seems like a hacky workaround and not how it should be done.
var equatableShapeContainerGame: Game<EquatableShapeContainer>
EquatableShape is a protocol inheriting Equatable and indeed every type conforming to EquatableShape is also conforming to Equatable.
CircleES on the other hand is a struct (ie. a concrete type) conforming to EquatableShape.
Only concrete types can conform to protocol and that is why
var circleESGame: Game<CircleES>
does compile.
With :
var equatableShapeGame: Game<EquatableShape>
You are passing a protocol inheriting Equatable when the generic constraints asks for a concrete type conforming to Equatable

swift protocol method when associated meets a constraint

I have a protocol with associated type.
I want the protocol to impose some method only if the associated type conforms to Equatable.
Something like this:
public protocol ListOfThings {
associatedtype ThingType
func append(_ thing: ThingType)
// This function makes sense only if ThingType is equatable
func remove(_ thing: ThingType) where ThingType: Equatable
}
I just can't find the right syntax for that.
I also tried with an extension, but the compiler (rightly) claims for the function body.
extension ListOfThings where ThingType: Equatable {
func remove(_ thing: ThingType)
}
To make #matt's comment concrete, this is in fact two protocols with different constraints. So give those different things different names:
public protocol ListOfThings {
associatedtype ThingType
func append(_ thing: ThingType)
}
// This requires that anything conforming to RemovableListOfThings
// also conform to ListOfThings, and that ThingType conform to Equatable,
// and that the type also implements `remove`.
public protocol RemovableListOfThings: ListOfThings
where ThingType: Equatable {
func remove(_ thing: ThingType)
}
What you're trying to do can't work since a type might be conformed to Equatable in another module. The compiler can't go back and revoke the conformance to ListOfThings just because the type is later conformed to Equatable (thus changing the requirements retroactively).

Set of protocols

Suppose I have this:
protocol MyStuff: Hashable {
var stuff: String { get }
}
extension MyStuff {
func hash(into hasher: inout Hasher) {
hasher.combine(stuff)
}
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.stuff == rhs.stuff
}
}
struct Stuff: MyStuff {
let stuff: String
}
Where I have a protocol which conforms to Hashable, and I extend that protocol to implement the requirements of Hashable. This works great.
I'm now trying to use the api like this:
let set: Set<MyStuff> = [Stuff(stuff: "Stuff")]
However I get this error:
Protocol 'MyStuff' as a type cannot conform to 'Hashable'
This question is actually a follow up to this answer written by George, and in that answer it says that
I believe SE-0309 (Unlock existentials for all protocols) could fix this.
I was wondering if that (the above link) would actually apply into this situation (listed in the code block above), as I'm having trouble fully understanding the proposal.
There are a couple of issues here, not necessarily due to the code you wrote, but due to how Swift is currently designed:
Protocols don't conform to other protocols, which means that MyStuff is not a sub-type of Hashable, which means you cannot use it as argument for the generic Set
Protocols with associated types, or self requirements, like Equatable, from which Hashable derives, can't be used as generic arguments, can only be used as generic constraints
The compiler runs into issue #1 from above, and that one gives the (clear maybe) message that protocols as types cannot be used as generic arguments instead of other protocols.
SE-0309 might solve issue #2, however you're stuck on #1, so you'll have to change your design.
Solutions? As others have suggested in the comments:
use a type eraser (e.g. https://stackoverflow.com/a/64476569/1974224)
use classes, and replace the protocol by a base class

Swift associated types and protocol inheritance

I'm using Swift 2.2 and I declared a protocol with associated type as follow:
protocol CollectionViewModeling {
associatedtype CellType
func cellAtIndexPath(indexPath: NSIndexPath) -> CellType
}
Now I have a view model protocol conform to the above protocol :
enum MyItemCell {
case MyItemCell1, MyItemCell2
}
protocol ItemsListViewModeling: CollectionViewModeling {
associatedtype CellType = MyCell
}
Finally, somewhere else, I want to declare a var that is conform to le protocol ItemsListViewModeling :
var viewModel: ItemsListViewModeling
And I'm getting this error :
Protocol 'ItemsListViewModeling' can only be used as a generic constraint because it has Self or associated type requirements
But I can easily create a class that implements this protocol.
Is it possible to declare a var to an associated typed protocol ? As I'm giving the final type of the associated type in the protocol ItemsListViewModeling, I don't understand why am I seeing this error from the compiler.
Thanks
See there stackoverflow.com
You can't treat protocols with associated types like regular protocols
and declare them as standalone variable types.

Why use class only protocols in Swift?

Can anyone please explain class only protocols to me in Swift. I understand what protocols are and why we use them. I also understand that its recommended to use class only protocols when we use reference type objects in it and want to limit the protocol conformation to classes only. However, I can't find any good answer to support that recommendation. Why is it recommended? What is the drawbacks of using normal protocols in that case.
One use case:
You have a "delegate" protocol and someone wants to have a weak property of that protocol type. weak can only be used on reference types; therefore, the protocol must be class-only.
Another use case used to be to extend reference types to adopt protocols. You can't extend AnyObject itself (to inherit from another protocol, or for any other reason) but you have any reference types you want adopt a protocol inherited from AnyObject.
For example, having class equality based on unique identity is often a perfectly fine solution, so you could adopt EquatableObject:
public protocol EquatableObject: AnyObject, Equatable { }
public extension EquatableObject {
static func == (class0: Self, class1: Self) -> Bool {
class0 === class1
}
}
But now, we have protocol extension constraints (using where clauses), so instead of extending AnyObject, we can extend the protocol, and use AnyObject as a constraint. It looks backwards but operates identically, and removes the need for our own protocol. 🥳
public extension Equatable where Self: AnyObject {
static func == (class0: Self, class1: Self) -> Bool {
class0 === class1
}
}