Last active
April 21, 2018 19:16
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: 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