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

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

Related

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).

Requiring, for a protocol, that an instance variable conform to a protocol ; rather than have a specific type

As part of a custom Coder, I convert both Float and Double in the exact same way :
static func encode(_ value : Double) -> Data {
withUnsafeBytes(of: value.bitPattern.bigEndian) { Data($0) }
}
static func encode(_ value : Float) -> Data {
withUnsafeBytes(of: value.bitPattern.bigEndian) { Data($0) }
}
I thought that instead I could require that value would conform to a protocol, and since the FloatingPoint protocol does not guarantee the presence of bitPattern, I thought I would make my own :
protocol CompatibleFloatingPoint {
var bitPattern : FixedWidthInteger { get }
}
This, however, gives the following error :
Protocol 'FixedWidthInteger' can only be used as a generic constraint because it has Self or associated type requirements
However, I cannot replace FixedWidthInteger with a specific type, as Double.bitPattern is a UInt64 and Float.bitPattern is a UInt32
What is the proper syntax to require that bitPattern conform to the FixedWidthInteger protocol without forcing it to have a specific type ?
What you're looking for is an associated type. This means exactly what you've described (the required type conforms to a protocol rather than being the existential of that protocol):
protocol CompatibleFloatingPoint {
associatedtype BitPattern: FixedWidthInteger
var bitPattern : BitPattern { get }
}
extension Float: CompatibleFloatingPoint {}
extension Double: CompatibleFloatingPoint {}
For more details, see Associated Types in the Swift Programming Language.

Type 'Response' does not conform to protocol 'Decodable' \ 'Encodable'

class ErrorObj: NSObject,Codable {
var numError:Int = 0
var DescriptionError = ""
}
class Response<T: Codable>: NSObject, Codable {
var error:ErrorObj!
var result:T!
func getResponse(errorObj:(ErrorObj)->Void,sucssesObj:(T)->Void) {
if error.numError != 0 {
errorObj(error)
} else{
sucssesObj(result)
}
}
}
errors:
Cannot automatically synthesize 'Decodable' because 'T?' does not conform to 'Decodable'
Protocol requires initializer 'init(from:)' with type 'Decodable'
Cannot automatically synthesize 'Decodable' because 'T?' does not conform to 'Encodable'
Protocol requires initializer 'init(from:)' with type 'Encodable'
The issue is caused by the fact that you declared both properties of Response as implicitly unwrapped optionals (IOU). The compiler cannot autogenerate the required methods of Codable for IOU properties.
However, there's no need to make those IOU anyways. If they are required properties that are always present in the response, make them non-optional. If they might be missing, make them Optional (use ? instead of !).
Also, Swift is not Objective-C. There's no need to make your types inherit from NSObject. And you should also use structs instead of classes unless you explicitly need reference type behaviour. You should also make all properties immutable unless you explicitly need to be able to mutate them.
struct ErrorObj: Codable {
let numError: Int
let description: String
}
struct Response<T: Codable>: Codable {
let error: ErrorObj
let result: T
func getResponse(errorObj: (ErrorObj) -> Void, successObj: (T) -> Void) {
if error.numError != 0 {
errorObj(error)
} else{
successObj(result)
}
}
}

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

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>()
}

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.