Filozoff
(Kamil Wyszomierski)
1
Hi,
Currently Swift allows to use a simple associated type:
protocol ExampleProtocol {
associatedtype Element
func exampleMethod(with element: Element)
}
But what if we want to use exampleMethod(with:) with generic Element?
To make protocols even more flexible I propose:
protocol ExampleProtocol {
associatedtype Element<T>
func exampleMethod<T>(with element: Element<T>)
}
Which allows to make default protocol implementation with generic associated type:
extension ExampleProtocol {
func exampleMethod<T>(with element: Element<T>) {
// (...)
}
}
and allows to fullfill protocol requirements for generic nested type:
class ExampleClass: ExampleProtocol {
enum Element<K> {
case new(K)
case old(K)
}
}
Simple example:
protocol Servicing {
associatedtype Response<K>
func request<T>(expecting result: (_ response: Response<T>) -> Void)
}
extension Servicing {
func request<T>(expecting result: (_ response: Response<T>) -> Void) {
// (...)
}
}
class StreamService: Servicing {
enum Response<K> {
case stream(K)
case failure(error: Error)
}
}
class DataService: Servicing {
enum Response<K> {
case data(K)
case failure(error: Error)
}
}
class Client {
func streamVideo() {
let service = StreamService()
service.request { (response: Response<Video>) in
switch response {
case .failure(let error):
print(error)
case .stream(let data):
break
}
}
}
func getUsername() {
let service = DataService()
service.request { (response: Response<String>) in
switch response {
case .failure(let error):
print(error)
case .data(let data):
break
}
}
}
}
2 Likes
jrose
(Jordan Rose)
2
It's come up before:
There are certainly use cases for it, but it's not easy to implement. I I think it counts as a limited form of "higher-kinded types", which have been discussed a few times as well (though in a slightly different form).
+1. Just encountered a case where I need this. Essentially, I need a protocol describing a Functor.
I have a code that takes collection of X, and reports the same collection, but now of Y and Z. If collection is an array of X, I should be getting arrays of Y and Z. If collection is a dictionary, I should be getting dictionaries with the same keys, but with values of Y and Z. If collection is generic struct S<T> with several named fields of type T, then sending S<X>, I should be getting S<Y> and S<Z>, etc.
Since in my case I have a limited set of target types, I was able to workaround this by making a protocol with two associated types:
class XMappable {
associatedtype YResult
associatedtype ZResult
func mapX(_ f: (X) -> Y) -> YResult
func mapX(_ f: (X) -> Z) -> ZResult
}
tcldr
4
Sounds like Rust has now implemented exactly this:
3 Likes
sighoya
5
Still experimental because of some scenarios to fix.
See Tracking Issue