Filozoff
(Kamil Wyszomierski)
November 9, 2018, 7:31am
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)
November 9, 2018, 4:35pm
2
It's come up before:
I have a model like this:
protocol Promise {
associatedtype Result
}
protocol Scanner {
associatedtype ScanPromise: Promise
func promiseScan<T>(from: Offset, until: (Offset, Item) -> T?) -> ScanPromise // where Result == T?
}
The thing that Iām trying to express is: whichever type implements the associated type āScanPromiseā must be generic, and that parameter must be its result (i.e. something it got as a result of calling the āuntilā closure).
Even with SE-0142, this kind ā¦
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).
Hello,
A potent problem in my experience with Swift has been the lack of a way to generalize code that is repetitive on the basis of higher kinded types. For the uninitiated, higher kinded types are the ability to reason about generic types with their type parameters as variable. For example, the Haskell definition for Functor, and a corresponding definition for Maybe (Haskell's equivalent to Optional)
typeclass Functor f where
fmap :: (a -> b) -> f a -> f b
instance Functor ā¦
+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
December 11, 2020, 9:01am
4
Sounds like Rust has now implemented exactly this:
I saw a recent Reddit post on the advances in Generic Associated Types (GATs) in Rust, which allows for the definition of a Monad trait. In this post, I'm going to take it one step further: a monad transformer trait in Rust!
3 Likes
sighoya
December 11, 2020, 4:00pm
5
Still experimental because of some scenarios to fix.
See Tracking Issue