This is a pretty awesome trick I have used a few times. Unfortunately, because Swift does not have higher-ranked types we cannot pass a generic function to call. The good news is that we don't have to hard code the function that gets called (foo
in the above example). There are many variations on this trick and a very useful one to know is how to use a "receiver" protocol to do double dispatch:
protocol _ReceiveP {
func _receiveP<T: P>(_: T)
}
extension P {
func _openP<Receiver: _ReceiveP>(for receiver: Receiver) {
receiver._receiveP(self)
}
}
extension Bar {
func doSomethingWithPs(_ ps: [P]) {
for p in ps {
p._openP(for: self)
}
}
func _receiveP<T: P>(_ value: T) {
// do somehing with value
}
}
I hope you can imagine several variations on this theme. For example, you can pass dynamic context through the dispatch, you can have a receive method that returns a value which is directly returned by the open method, etc.