Skip to content

Instantly share code, notes, and snippets.

@marcpalmer
Last active April 21, 2018 19:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcpalmer/9f59bc787d2cfa0336c57dcf29420c76 to your computer and use it in GitHub Desktop.
Save marcpalmer/9f59bc787d2cfa0336c57dcf29420c76 to your computer and use it in GitHub Desktop.
Shows a problem where it seems impossible to split a protocol with associated types to use composition and still be able to use discriminated on type
//: Playground - noun: a place where people can play
import UIKit
protocol Action {
associatedtype Input
associatedtype Presenter
static func present(i: Input, p: Presenter)
}
extension Action {
static func present(i: TestAction.Input, p: TestAction.Presenter) {
print(i)
}
}
protocol AnalyticsTrackable {
associatedtype Input where Input: CustomStringConvertible
static var analyticsID: String { get }
static func attributes(for i: Input)
}
extension AnalyticsTrackable {
static func attributes(for i: TestAction.Input) {
}
}
class SomeInput: CustomStringConvertible {
let value: String = "something"
var description: String { return value }
}
final class TestAction: Action, AnalyticsTrackable {
typealias Input = SomeInput
typealias Presenter = Any
static var analyticsID = "test"
}
protocol Observer {
func actionDidComplete<T>(action: T.Type) where T: Action
}
class TestObserver: Observer {
func actionDidComplete<T>(action: T.Type) where T: Action {
print("Completed: \(action)")
// This is the part that breaks, as expected with PATs, but it's not clear if there is any workaround.
// You cannot overload `actionDidComplete` for different type constraints as Swift will not select the correct one
if let analyticsAction = action as? AnalyticsTrackable.Type {
print("Analytics ID: \(analyticsAction.analyticsID)")
}
}
// This does NOT work, as it understandably only resolves to the statically type method generic on Action:
/*
func actionDidComplete<T>(action: T.Type) where T: Action {
func actionDidComplete<T>(action: T.Type) where T: Action {
print("Completed: \(action)")
}
func actionDidComplete<T>(action: T.Type) where T: Action & AnalyticsTrackable {
print("Completed: \(action)")
print("Analytics ID: \(action.analyticsID)")
}
*/
}
let observer = TestObserver()
func dispatch<T>(action: T.Type, input: T.Input, presenter: T.Presenter) where T: Action {
action.present(i: input, p: presenter)
observer.actionDidComplete(action: action)
}
dispatch(action: TestAction.self, input: SomeInput(), presenter: "UI")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment