I know how to customize binary operators, like this
infix operator ** { associativity left precedence 170 }
func ** (left: Double, right: Double) -> Double {
return pow(left, right)
}
But, how to customize ternary operators in Swift? Can anyone give me some idea? Thanks so much!
1 Ternary Operator in Swift. The ternary conditional operator is used to shorten the code of the if statement. ... 2 Example: Swift Ternary Operator. You pass the exam. ... 3 Ternary operator rather than if…else. The ternary operator can be used to replace specific types of if…else statements. ... 4 Nested Ternary Operators. ...
A ternary operator evaluates a condition and executes a block of code based on the condition. Its syntax is Here, the ternary operator evaluates condition and if condition is true, expression1 is executed. if condition is false, expression2 is executed.
Unlike the arithmetic operators in C and Objective-C, the Swift arithmetic operators don’t allow values to overflow by default. You can opt in to value overflow behavior by using Swift’s overflow operators (such as a &+ b ). See Overflow Operators. The addition operator is also supported for String concatenation:
Effectively, the addition and the assignment are combined into one operator that performs both tasks at the same time. The compound assignment operators don’t return a value. For example, you can’t write let b = a += 2. For information about the operators provided by the Swift standard library, see Operator Declarations.
You can actually do this by declaring two separate operators that work together and using a curried function for one of the operators.
Let's declare a ternary operator x +- y +|- z
that will check the sign of the initial value x
, and then return the second value y
if the sign is zero or positive and the final value z
if the sign is negative. That is, we should be able to write:
let sign = -5 +- "non-negative" +|- "negative"
// sign is now "negative"
We'll start by declaring the two operators. The important part is to have higher precedence on the second operator - we'll evaluate that part first and return a function:
infix operator +- { precedence 60 }
infix operator +|- { precedence 70 }
Then define the functions - we'll define the second first:
func +|-<T>(lhs: @autoclosure () -> T, rhs: @autoclosure () -> T)(left: Bool) -> T {
return left ? lhs() : rhs()
}
The important part here is that this function is curried -- if you only call it with the first two parameters, instead of returning a T
value, it returns a (left: Bool) -> T
function. That becomes the second parameter of the function for our first operator:
func +-<I: SignedIntegerType, T>(lhs: I, rhs: (left: Bool) -> T) -> T {
return rhs(left: lhs >= 0)
}
And now we can use our "ternary" operator, like this:
for i in -1...1 {
let sign = i +- "" +|- "-"
println("\(i): '\(sign)'")
}
// -1: '-'
// 0: ''
// 1: ''
Note: I wrote a blog post on this subject with another example.
precedencegroup SecondaryTernaryPrecedence {
associativity: right
higherThan: TernaryPrecedence
lowerThan: LogicalDisjunctionPrecedence
}
infix operator ~ : SecondaryTernaryPrecedence
func ~ <T>(lhs: @autoclosure () -> Bool, rhs: @escaping @autoclosure () -> T) -> (Bool, () -> T) {
return (lhs(), rhs)
}
infix operator >< : TernaryPrecedence
@discardableResult func >< <T>(lhs: (Bool, () -> T), rhs: @escaping @autoclosure () -> T) -> T {
if lhs.0 {
return lhs.1()
} else {
return rhs()
}
}
let n = false ~ "it was true" >< "it was false" //"it was false"
true ~ print("it was true") >< print("it was false")
// Prints "it was true"
Note: While this is not a true ternary operator per se, as it uses two infix operators in conjunction with one another, it does in fact somewhat emulate its behaviour when the two operators are used together in the fashion presented above.
A "true" ternary operator such as _ ? _ : _
requires language support. Swift allows creating and customizing only unary and binary operators.
You can use the technique in @NateCook's answer to make a pair of binary operators which together work like a ternary operator, but they're still independent binary operators -- you can use either on its own. (By contrast, _ ? _ : _
is only a ternary operator; _ ? _
and _ : _
can't be used individually.)
Of course, why stop there? You could chain more binary operators to create quaternary operators, and so on. For extra credit, try making yourself an extended spaceship operator:
let c: String = a <=> b
|<| "a < b"
|=| "a = b"
|>| "a > b"
(...but please do this as an academic exercise only, or anyone else who works with code you write will hate you.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With