The way Generics work in Swift is each specialized version is, for this purpose, it's own unique Type. So, Array<SuperClass> is a different Type from Array<ChildClass> the same way Array<String> and Array<Int> are different.
So while the Type of validator1 can be CompoundValidator<EmptyStringValidator>, there's no reasonable Type for validator2 (since it has to a concrete type, i.e. not a protocol).
I believe there will be better options for this in the future, but one current workaround would be to re-organize the structure a bit.
protocol Validator {
associatedtype ValidationType
func validate(_ value: ValidationType)
}
struct GenericValidator<ValidationType>: Validator {
let validation: (ValidationType) -> ()
init(validation: @escaping (ValidationType) -> ()) {
self.validation = validation
}
func validate(_ value: ValidationType) { validation(value) }
}
struct CompoundValidator<ValidationType>: Validator {
let validators: [GenericValidator<ValidationType>]
init(validators: [GenericValidator<ValidationType>]) {
self.validators = validators
}
func validate(_ value: ValidationType) { validators.forEach{$0.validate(value)} }
}
let emptyStringValidator = GenericValidator<String>.init{ print(!$0.isEmpty) }
let lengthValidator = GenericValidator<String>.init{ print($0.count > 10) }
// works
let validator1 = CompoundValidator(validators: [emptyStringValidator, emptyStringValidator])
validator1.validate("sample string")
// doesn't work "Cannot convert value of type 'EmptyStringValidator' to expected element type '_'"
let validator2 = CompoundValidator(validators: [emptyStringValidator, lengthValidator])
validator2.validate("sample string")