I am attepting to guard depending on the value of an enum...
This is a contrived example so bear with me...
public struct Invoice {
public enum EmailStatus {
case NeverSent
case SentPaymentDueNotice(attempts: Int)
case SentPaidNotice
}
public var name: String
public var email: String
public var total: Float
public var paid: Bool
public var emailStatus: EmailStatus
}
I would like to do something like the following...
public func email(invoice: Invoice) throws {
guard case .SentPaidNotice != invoice.emailStatus else { // ERROR: "Variable binding in a condition requires an initializer"
throw EmailError.AlreadySentPaidNotice
}
print("Sending invoice to\(invoice.name) <\(invoice.email)>")
}
Unfortunately I can only seem to get this working with the compiler
public func email(invoice: Invoice) throws {
guard case .SentPaidNotice = invoice.emailStatus else {
throw EmailError.AlreadySentPaidNotice
}
print("Sending invoice to \(invoice.name) <\(invoice.email)>")
}
Which is the inverse of what I want. I can only get this behavior using if instead of guard, like...
public func email(invoice: Invoice) throws {
if case .SentPaidNotice = invoice.emailStatus {
throw EmailError.AlreadySentPaidNotice
}
print("Sending invoice to \(invoice.name) <\(invoice.email)>")
}
It seems the if-case guard-case is only a binding operation, it would be nice if you could perform logical operations on it, or am I just missing something?
The way to think about this is in comparison with a switch:
switch invoice.emailStatus {
case .SendPaidNotice:
throw …
Note that the "case" is matching an expression that follows the 'switch' keyword. For "if case" or "guard case", you still need an expression, and the syntax happens to require it as an initializer:
guard/if case .SendPaidNotice = invoice.emailStatus
That's why you can't invert the test in the "guard case" statement — because you can't invert a case, period. However, as jawbroken pointed out, you don't need a case pattern at all, just a simple boolean expression. In short, all you had to do was leave out "case".
If that seems a bit confusing, I'd agree with you. The syntax of conditional patterns is hard to grasp, and I hope that a future version of Swift changes it to something a bit more predictable.