In Swift, the ternary operator easily allows us to clean and concisely write conditionally code. Although currently, the inability to use certain statements in conjunction with the ternary operator is limiting.
I am proposing the addition of 5 statements for usage in conjunction with the ternary operator:
All of these various statements will greatly improve the flexibility and ease of use with the ternary operator.
break
This will bring the use of the keyword break
to the ternary operator.
This will simplify:
if condition {
break
} else {
doSomething()
}
To:
condition ? break : doSomething()
Note: the break
statement can also be put in the second argument of the ternary operator too, this so the code would break
if the condition
was not met. A loop's label may be specified after the break
keyword as well.
Usage Example:
The following function, getPrimes(n:)
, returns the first n
prime numbers as an array of Int
s.
func getPrimes(n: Int) -> [Int] {
var primes = [Int]()
var count = 1
for x in 2... where !primes.contains { x % $0 == 0 } {
primes.append(x)
if count > n {
break
} else {
count += 1
}
}
return primes
}
print(getPrimes(n: 10))
// Prints "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]"
Now, let's fix this code using our new and refined syntax:
func getPrimesAgain(n: Int) -> [Int] {
var primes = [Int]()
var count = 1
for x in 2... where !primes.contains { x % $0 == 0 } {
primes.append(x)
count < n ? (count += 1) : break //syntactical change
//We can alternatively use:
//count += count < n ? 1 : break
}
return primes
}
print(getPrimesAgain(n: 10))
// Prints "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]"
fallthrough
This will bring the use of the keyword fallthrough
to the ternary operator.
This will simplify:
if condition {
fallthrough
} else {
doSomething()
}
To:
condition ? fallthrough : doSomething()
Note: the fallthrough
statement can also be put in the second argument of the ternary operator too, this so the code would fallthrough
if the condition
was not met.
Usage Example:
First let's start by creating our Fruit
enumeration.
enum Fruit {
case apple, pear, orange, banana, grapes
}
Now, let's create a function that takes a list (Array
) of the fruits we have in our fruit basket. We want this function to tells us if we have an apple in our basket, but otherwise, tell us that we just have some random fruits.
func fruitBasket(with fruits: [Fruit]) {
guard let firstFruit = fruits.first else { return }
var str = "We have "
switch fruits {
case let basket where basket.contains(.apple):
str.append("an apple and ")
if fruits.count > 1 {
fallthrough
} else {
str.removeLast(4)
}
default:
str.append("some other fruits")
}
print(str, "in our basket")
}
let fruits : [Fruit] = [.apple, .pear, .banana]
fruitBasket(with: fruits)
// Prints "We have an apple and some other fruits in our basket"
let applelessFruits : [Fruit] = [.pear, .orange, .grapes]
fruitBasket(with: applelessFruits)
// Prints "We have some other fruits in our basket"
Now, let's rejig our code above with our new and refined syntax:
func fruitBasketRefined(with fruits: [Fruit]) {
guard let firstFruit = fruits.first else { return }
var str = "We have "
switch fruits {
case let basket where basket.contains(.apple):
str.append("an apple and ")
fruits.count == 1 ? str.removeLast(4) : fallthrough //syntactical change
default:
str.append("some other fruits")
}
print(str, "in our basket")
}
let newFruits : [Fruit] = [.orange, .apple, .banana, .grapes]
fruitBasketRefined(with: fruits)
// Prints "We have an apple and some other fruits in our basket"
let newApplelessFruits : [Fruit] = [.pear, .orange, .grapes]
fruitBasketRefined(with: newApplelessFruits)
// Prints "We have some other fruits in our basket"
return
This will bring the use of the keyword return
to the ternary operator.
This will simplify:
if condition {
return someValue
} else {
doSomething()
}
To:
condition ? return someValue : doSomething()
Note: the return
statement and someValue
can also be put in the second argument of the ternary operator too, this so the code would return
someValue
if the condition
was not met.
Usage Example:
We want to make a function pythagoreanTripleGCF(a:b:c:)
where a
, b
, and c
are values of type Int
. If a
, b
, and c
form a pythagorean triple, our function will return the greatest common factor of a²
, b²
, and c²
. But if a
, b
, and c
do not form a pythagorean triple, our function will return -1
.
func pythagoreanTripleGCF(a: Int, b: Int, c: Int) -> Int {
let (x, y, z) = (a * a, b * b, c * c)
var n = -1
if x + y == z {
n = min(x, y, z)
} else {
return n
}
n = (1...n).reversed().first { x % $0 == 0 && y % $0 == 0 && z % $0 == 0 }!
return n
}
let a = 6
let b = 8
let c = 10
// 6² + 8² = 10², ∴ a, b, and c are a valid pythagorean triple
print(pythagoreanTripleGCF(a: a, b: b, c: c)) //The GCF of 36, 64, and 100 is 4
// Prints "4"
Now, let's update our code above with our new and improved syntax.
func betterPythagoreanTripleGCF(a: Int, b: Int, c: Int) -> Int {
let (x, y, z) = (a * a, b * b, c * c)
var n = -1
x + y == z ? (n = min(x, y, z)) : return n //syntactical change
n = (1...n).reversed().first { x % $0 == 0 && y % $0 == 0 && z % $0 == 0 }!
return n
}
let a = 6
let b = 8
let c = 10
// 6² + 8² = 10², ∴ a, b, and c are a valid pythagorean triple
print(betterPythagoreanTripleGCF(a: a, b: b, c: c)) //The GCF of 36, 64, and 100 is 4
// Prints "4"
continue
This will bring the use of the keyword continue
to the ternary operator.
This will simplify:
if condition {
continue
} else {
doSomething()
}
To:
condition ? continue : doSomething()
Note: the continue
statement can also be put in the second argument of the ternary operator too, this so the code would continue
if the condition
was not met. A loop's label may be specified after the continue
keyword as well.
Usage Example:
Let's start off by making a function called transformedEvens(of:with:)
. The first parameter, arr
, is of type [Int]
and this will be the array that we are preforming the specified transformation on. The second parameter, transform
, is of type (Int) -> Int
and this specifies the transformation to perform on each even integer in the array (arr
). After preforming the specified transformations on arr
, we will return our newly transformed array newArr
.
func transformedEvens(of arr: [Int], with transform: (Int) -> Int) -> [Int] {
var newArr = [Int]()
for var n in arr {
if n % 2 == 0 {
n = transform(n)
} else {
continue
}
newArr.append(n)
}
return newArr
}
let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let transformedArray = transformedEvens(of: array) { $0 * 10 }
print(transformedArray)
// Prints "[20, 40, 60, 80, 100]"
Now, let's take our transformedEvens
function and freshen it up with our new syntactical changes.
func transformedEvensV2(of arr: [Int], with transform: (Int) -> Int) -> [Int] {
var newArr = [Int]()
for var n in arr {
n % 2 == 0 ? (n = transform(n)) : continue //syntactical change
newArr.append(n)
}
return newArr
}
let newArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let newTransformedArray = transformedEvensV2(of: newArray) { $0 * 10 }
print(newTransformedArray)
// Prints "[20, 40, 60, 80, 100]"
Blank Argument `_
`
This will bring the use of the keyword break
to the ternary operator.
This will simplify:
if condition {
doSomething()
} else {
//empty
}
To:
condition ? doSomething() : _
Note: the blank `_
` argument can also be put in the first argument of the ternary operator too, this so doSomething()
would execute if the condition
was not met. If indeed condition
is false in the above line of code, the line will not be evaluated.
Usage Example:
Let's make a function called addEvens(from:to:)
. This function will take an array of Int
s, arr
, and return the value of each of its even integers added to n
.
func addEvens(from arr: [Int], to n: Int) -> Int {
var num = n
for i in arr {
if i % 2 == 0 {
num += i
}
}
return num
}
let number = 15
let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(addEvens(from: array, to: number))
// Prints "45"
Now, let's redo our code above with our new ternary syntax:
func addEvensFixed(from arr: [Int], to n: Int) -> Int {
var num = n
for i in arr {
i % 2 == 0 ? (num += i) : _ //syntactical change
//We can alternatively use:
//num += i % 2 == 0 ? i : _
}
return num
}
Ternary Operators that Return Values
Given the following code
var totalUnderTen = 0
for n in 1... {
totalUnderTen += n < 10 ? n : break
}
// totalUnderTen = 45 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
The code will be accepted as valid syntax and will break if the condition is true, rather than returning the value of break
so to say.
The same is true for all of the other aforementioned additions (break
, fallthrough
, _
, return
, continue
).
Motivation
The primary motivation for this addition to the ternary operator is ease of writing quick code. This will help extend the functionality of the loved ternary operator, especially when dealing with control flow.