Manuel Carlos asks whether it’s possible to create an operator that executes a closure and returns a value based on whether a condition is true. Here’s his initial attempt:
My recommendation? Skip the operator and just use an if-
statement:
if true { v = 100 } // vs v = 100 <-? true if false { v = 100 } // vs v = 100 <-? false if true { print("hello") } // vs print("hello") <-? true if false { print("hello") } // vs print("hello") <-? false
Yes, it’s simple, but simple gets the job done without straining or extending the language. There’s little gained in building a more complex logic-driven assignment for this use case. Placing a truth statement to the right of each action inverts the normal way people read code, burns an operator, abuses auto-closure, and unnecessarily complicates what should be a straightforward operation.
That’s not to say this isn’t an interesting design space. Although Swift does not support custom ternary operators at this time, it may do so at some point in the future. Even then, I’d be cautious about replacing if
-then control with such complex solutions.
Apple’s recommendations on auto-closure are:
- Use autoclosure carefully as there’s no caller-side indication that argument evaluation is deferred.
- The context and function name should make it clear that evaluation is being deferred.
- Autoclosures are intentionally limited to take empty argument lists.
- Avoid autoclosures in any circumstance that feels like control flow.
- Incorporate autoclosures to provide useful semantics that people would expect (for example, a “futures” or “promises” API).
- Don’t use autoclosures to optimize away closure braces.
Want to read more about Swift Style? There’s a book!
2 Comments
There’s actually a way to write (kind-of) ternary operators in Swift:
infix operator ???: TernaryPrecedence
infix operator |||: TernaryPrecedence
func |||(
lhs: @autoclosure @escaping () -> A,
rhs: @autoclosure @escaping () -> A
) -> (Bool) -> A {
return { cond in
if cond {
return lhs()
} else {
return rhs()
}
}
}
func ???(lhs: Bool, rhs: (Bool) -> A) -> A {
return rhs(lhs)
}
false ??? "a" ||| true ??? "b" ||| "c" // "b"
Thanks Erica!! Didn’t know about apple recommendations regarding auto-closures. Great Post!