1

I want to create a Validatable protocol that has two properties: a validator and an isAbleToProceed boolean:

protocol Validatable {
    var validator: Validator { get set }
    var isAbleToProceed: Bool { get set }
}

I want to define different types of Validators (date of birth validator, email validator, etc.). To do so I created a factory:

protocol Validator {}

struct ValidatorFactory {
    internal static let sharedInstance = ValidatorFactory()

    func dateOfBirthValidator(minimumAge: Int, maximumAge: Int) -> DateOfBirthValidator {
        return DateOfBirthValidator(minimumAge: minimumAge, maximumAge: maximumAge)
    }

    func driversLicenseValidator(minLicenseDuration: Int) -> DriversLicenseValidator {
        return DriversLicenseValidator(minLicenseDuration: minLicenseDuration)
    }
}

and this is the implementation of DateOfBirthValidator:

struct DateOfBirthValidator: Validator {
    let minimumAge: Int
    let maximumAge: Int

    func isDateOfBirthValid(date: Date) -> Bool {
        if let age = Calendar.current.dateComponents([.year], from: date, to: Date()).year {
            return (minimumAge ... maximumAge).contains(age)
        } else {
            return false
        }
    }
}

Then I would have a class, ViewController, implementing the Validatable protocol:

class ViewController: Validatable {

    // MARK: Internal Properties

    internal var validator: DriversLicenseValidator
    internal var isAbleToProceed: Bool = false

}

But the compiler would report that ViewController does not conform to Validatable (does not have a Validator)

This can be solve if I make Validator a superclass and all the validators structs turn into classes and inherit from it. But is there a way to make it work with structs and protocols?

gmoraleda
  • 1,731
  • 1
  • 17
  • 44

1 Answers1

2

This question is almost a duplicate of yours, except that it asks why a get-only property can't be satisfied through protocol conformance. The answer there is that, in theory it could, but right now you can't. There are a couple of Swift bugs on this

  • A generic bug that covers variations on this issue and
  • A specific bug which is almost exactly your question and was closed as a duplicate of the first.

Now, in your case you have a get/set property (at least as it is declared in the protocol; you made it let in your implementation).

Because of the Liskov Subsitution Principle I should be able to say:

var someValidatable = ViewController() as Validatable
someValidateable.validator = SocialSecurityValidator()

If you were able to do what you want, this would fail for two reasons:

  1. validator has a more restricted access and is let instead of var
  2. A SocialSecurityValidator can't be assigned to validator because it is of type DriversLicenseValidator
Paulw11
  • 108,386
  • 14
  • 159
  • 186