Given this enum which represents the response from a network call:
public enum Response<T: Model> {
case success(T)
case failure(Error)
}
It can represent a response with a single Model. What I'm wondering is: is there is a way to constraint T so it can be either a single Model or an array Model?
Right. It's only available in ToT compiler, and only under a special flag, IIRC.
The next best thing I can think of is wrapping the array of models into a trivial struct and make this struct conform to the protocol. Should be essentially the same for a small price, that is, you'd have to instantiate this new struct manually.
Even then, you won't be able to. It was explicitly ruled out.
Extending protocols to conform to protocols
The most common request related to conditional conformances is to allow a (constrained) protocol extension to declare conformance to a protocol. For example:
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.
You could add a conformance to the concrete Array type, though.
extension Array: Model where Element: Model {
// ...
}
I'm assuming this doesn't fix your problem, but this is how I see it:
You want to accept either a Model instance (exactly one), or an array of Model instances (between 0...n).
So the case of accepting exactly one instance is actually a subset of accepting an array anyway.
Maybe there is a semantic difference in your case between receiving a Model instance and receiving a [Model] instance that contains exactly one element. But if not, I'd simplify to:
public enum Response<T: Model> {
case success([T])
case failure(Error)
}
I'll end up doing the everything is an array approach because I'm having too much trouble otherwise. I just wanted the caller to receive exactly what he wanted and I was wondering if it would be possible.
For future reference, this was my last attempt before deciding to go with the array everywhere approach:
public protocol Service {
func get<T>(path: String, parameters: [String: Any], completion: @escaping (Response <T>) -> Void) where T: Model
func get<T: Collection>(path: String, parameters: [String: Any], completion: @escaping (Response <T>) -> Void) where T.Element: Model
}
public enum Response<T> {
case success(T)
case failure(Error)
}
I was liking it at first but it started to require having "duplicated" methods everywhere.