Reputation: 17231
I have an enum that I use for text validation defined as follows:
enum Validity {
case valid
case invalid(reason: String)
}
My TextValidator
has a function that checks a text input and returns a Validity
:
func validate(_ string: String) -> Validity
which is convenient because in case of an error I can display the validation failure reason to the user without much effort.
In many cases, however, I simply need a boolean check if the string is valid – for example for enabling / disabling a submit button. The code that I'm using for this right now is:
let validity = validator.validate("user input string")
submitButton.isEnabled = (validity == .valid)
which is kind of bad to read and thus, I would prefer to write something like:
let isValid: Bool = validator.validate("user input string")
submitButton.isEnabled = isValid
or shorter:
submitButton.isEnabled = validator.validate("user input string")
As a "quick fix" I have defined a computed boolean property isValid
on my Validity
enum so I can at least write:
submitButton.isEnabled = validator.validate("user input string").isValid
but it seems kind of verbose to me to append .isValid
to a validation result and I would very much prefer to directly check the validity and treat it as a boolean when used in a context that expects a boolean via type inference.
So my question is:
Bool
in Swift?Or if not: Can you think of another approach that retains the advantages of both – the Bool and the enum type?
Upvotes: 2
Views: 2257
Reputation: 154593
You can achieve this by overloading your validate
function to also return Bool
.
enum Validity {
case valid
case invalid(reason: String)
}
// Example validate function
func validate(_ string: String) -> Validity {
if string.count < 5 {
return .valid
} else {
return .invalid(reason: "String too long")
}
}
// Overloaded function which returns Bool
func validate(_ string: String) -> Bool {
let validity: Validity = validate(string)
if case .valid = validity {
return true
} else {
return false
}
}
// Swift expects the result of validate to be a Bool, so it calls the
// (String) -> Bool version of validate
let b1: Bool = validate("this")
print(b1)
true
// Here, the result of validate is used in an if, so Swift is expecting
// a Bool result and calls the (String) -> Bool version of validate
if validate("this is a test") {
print("the string is valid")
} else {
print("the string is invalid")
}
the string is invalid
let v: Validity = validate("what about this one?")
switch v {
case .valid:
print("valid")
case .invalid(let reason):
print("invalid: \(reason)")
}
invalid: String too long
Upvotes: 2