I have a protocol, Address
, which inherits from another protocol, Validator
, and Address
fulfills the Validator
requirement in the extension.
There is another protocol, FromRepresentable
, which has an associatedType
(ValueWrapper
) requirement which should be Validator
.
Now if I try to use Address
as associatedType
, then it does not compile. It says,
Inferred type 'Address' (by matching requirement 'valueForDetail') is invalid: does not conform to 'Validator'.
Is this usage illegal? Shouldn't we be able to use Address
in place of Validator
, as all Addresses
are Validator
.
Below is the piece of code I am trying.
enum ValidationResult {
case Success
case Failure(String)
}
protocol Validator {
func validate() -> ValidationResult
}
//Address inherits Validator
protocol Address: Validator {
var addressLine1: String {get set}
var city: String {get set}
var country: String {get set}
}
////Fulfill Validator protocol requirements in extension
extension Address {
func validate() -> ValidationResult {
if addressLine1.isEmpty {
return .Failure("Address can not be empty")
}
return .Success
}
}
protocol FormRepresentable {
associatedtype ValueWrapper: Validator
func valueForDetail(valueWrapper: ValueWrapper) -> String
}
// Shipping Address conforming to Address protocol.
// It should also implicitly conform to Validator since
// Address inherits from Validator?
struct ShippingAddress: Address {
var addressLine1 = "CA"
var city = "HYD"
var country = "India"
}
// While compiling, it says:
// Inferred type 'Address' (by matching requirement 'valueForDetail') is invalid: does not conform
// to 'Validator'.
// But Address confroms to Validator.
enum AddressFrom: Int, FormRepresentable {
case Address1
case City
case Country
func valueForDetail(valueWrapper: Address) -> String {
switch self {
case .Address1:
return valueWrapper.addressLine1
case .City:
return valueWrapper.city
case .Country:
return valueWrapper.country
}
}
}
Update: Filed a bug.
You've got a several issues:
First of all, you don't actually declare that Address implements Validator
And you don't declare the associated type for ValueWrapper:
And you seem to actually be wanting AddressFrom.valueForDetail to take a
ShippingAddress
:Altogether, it looks like:
The problem, which David has already alluded to, is that once you constrain a protocol's
associatedtype
to a specific (non@objc
) protocol, you have to use a concrete type to satisfy that requirement.This is because protocols don't conform to themselves – therefore meaning that you cannot use
Address
to satisfy the protocol's associated type requirement of a type that conforms toValidator
, asAddress
is not a type that conforms toValidator
.As I demonstrate in my answer here, consider the counter-example of:
The simplest solution would be to ditch the
Validator
protocol constraint on yourValueWrapper
associated type, allowing you to use an abstract type in the method argument.If you need the associated type constraint, and each
AddressFrom
instance only expects a single concrete implementation ofAddress
as an input – you could use generics in order for yourAddressFrom
to be initialised with a given concrete type of address to be used in your method.However, if you require both the associated type constraint and each
AddressFrom
instance must be able to handle an input of any type ofAddress
– you'll have use a type erasure in order to wrap an arbitraryAddress
in a concrete type.