Idea: Making "if expression" else part optional

I don't want to spam the "Last expression as return value" thread as this is orthogonal.


Could we make the else branch of if expressions optional?

let x: Int? = if condition { 42 }

to mean the same as:

let x: Int? = if condition { 42 } else { nil }

Example:

    let items: [Int] = (0 ..< 20).compactMap { i in
        if (i % 2) == 0 {
            i
        }
    }
    print(items) // [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

This change is additive.

3 Likes

You can achieve something similar with an extension on Bool already now:

extension Bool {
  func ifTrue<T>(_ value: @autoclosure () -> T) -> T? {
    self ? value() : nil
  }
}

With this extension you can write code like

print(true.ifTrue(1)) // Optional(1)
print((4 % 2 == 0).ifTrue("4 is even")) // Optional("4 is even")
print((3 % 2 == 0).ifTrue("3 is even")) // nil
print((3 % 2 == 0).ifTrue("3 is even") ?? "3 is odd") // 3 is odd

Without @autoclosure you can even create a syntax that's very close to what you propose.

2 Likes

Optionals already have too much special treatment and I wouldn't like them getting even more, but I'd still use this anyway. But only if the conditional operator is divorced from being ternary, as well.

let x: Int? = condition ? 42

This is filter.

let items = (0..<20).filter { $0.isMultiple(of: 2) }

Optional.filter is missing from the standard library.

let x = _?(42).filter(condition)

let items = (0 ..< 20).compactMap {
  ($0 as _?).filter { $0.isMultiple(of: 2) }
}
public extension Optional {
  func filter<Error>(_ isSome: (Wrapped) throws(Error) -> Bool) throws(Error) -> Self {
    try flatMap { wrapped throws(Error) in try isSome(wrapped) ? wrapped : nil }
  }

  func filter(_ isSome: Bool) -> Self {
    filter { _ in isSome }
  }
}

Sure, let's make it more interesting:

    let items: [Int] = (0 ..< 20).compactMap { i in
        if condition(i) {
            transform(i)
        }
    }
1 Like

Other @SimplyDanny has the right idea but it's expressible as an "? overload" with different spelling.

let items = (0..<20).compactMap { condition($0) ??? transform($0) }
infix operator ???

func ??? <Wrapped>(isSome: Bool, wrapped: @autoclosure () -> Wrapped) -> Wrapped? {
  isSome ? wrapped() : nil
}
1 Like