[swift-evolution] ternary operator ?: suggestion

Howard Lovatt howard.lovatt at gmail.com
Tue Dec 29 01:53:41 CST 2015


You can replace the proposed statement `which` (another thread), the existing statement `?:` (this thread), and the global function `??` (which is an odd ball) with matching library methods.

A library method is likely slower than a built in at this stage until the optimiser improves, but a library function:

Is documented right in the IDE including code completion, statements aren’t (you don’t see quick help for `for`!)
Having a library function allows the use case to be throughly investigated. Is worth while as a language statement? What exact features are useful? EG should `which` support pattern matching, general boolean expressions, or simply be `Equatable` as shown below?
It is simpler to implement, maintain, and change a library function that a built-in.
There is no need for a keyword.

First `which`:

// Alternative to introducing `which` statement

final
class Which<I: Equatable, R> {
    private
    var result: R?
    
    private
    let which: I
    
    init(_ which: I) {
        self.which = which
    }
    
    func match(value: I, @noescape matchResult: () throws -> R) rethrows -> Self {
        if self.result == nil && self.which == value {
            self.result = try matchResult()
        }
        return self
    }
    
    func matchDefault(@noescape defaultResult: () throws -> R) rethrows -> R {
        switch self.result {
        case .None:
            return try defaultResult()
        case .Some(let value):
            return value
        }
    }
}


// Demo
enum Color {
    case Red, Blue, Green
}

// Which with a default value
let i1 = Which(Color.Red) // i = 16711680
    .match(.Red)   { 0xFF0000 }
    .match(.Green) { 0x00FF00 }
    .match(.Blue)  { 0x00000FF }
    .matchDefault  { 0 }

// Which that throws an error if it defaults
let i2: Int! = Which(Color.Green) // i = 16711680
    .match(.Red)   { 0xFF0000 }
    .match(.Green) { 0x00FF00 }
    .match(.Blue)  { 0x00000FF }
    .matchDefault  { nil }  // Cant type call to fatalError as no return, hence nil and type Int! (note !)

Note runtime check for default rather than static check via compiler, not as good but not a big deal most of the time. The vast majority of languages don't do a compiler check on `switch`.

Similarly the `?:` statement can be replaced:

// Replacement for `?:` operator

struct IfFalse<R> {
    private
    let result: R?
    
    func ifFalse(@noescape falseResult: () throws -> R) rethrows -> R {
        switch self.result {
        case .None:
            return try falseResult()
        case .Some(let value):
            return value
        }
    }
}

extension Bool {
    func ifTrue<R>(@noescape trueResult: () throws -> R) rethrows -> IfFalse<R> {
        switch self {
        case true:
            return IfFalse(result: try trueResult())
        case false:
            return IfFalse(result: nil)
        }
    }
}


// Demo
let sB = true.ifTrue{"True"}.ifFalse{"False"} // "True" - for some reason needs {} and not () thinks () form throws

Whilst the `??` operator is already a library function it is difficult to see in an expression, it gets buried, and is inconsistent in style because it is a non-mathematical operator and a symbol rather than a keyword or keyword followed by a symbol. The space either side of the `??` operator also makes it look like both arguments are of equal importance, whereas it is the left hand side that is important and the right hand side is just a catch.

// Replacement for `??` operator

extension Optional {
    func ifNil(@noescape nilResult: () throws -> Wrapped) rethrows -> Wrapped {
        switch self {
        case .None:
            return try nilResult()
        case .Some(let value):
            return value
        }
    }
}


// Demo
let o: String? = nil
let sO = o.ifNil{"Nil"} // "Nil" - for some reason needs {} and not () thinks () form throws


Sent from my iPad

> On 29 Dec 2015, at 4:00 AM, Thorsten Seitz via swift-evolution <swift-evolution at swift.org> wrote:
> 
> No exhaustiveness checking is a serious deficiency :-(
> 
> -Thorsten
> 
>> Am 17.12.2015 um 08:09 schrieb Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org>:
>> 
>> Actually, this *almost* does what you want. No @autoclosure for the values and no exhaustiveness checking, but otherwise...
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151229/83bbc385/attachment.html>


More information about the swift-evolution mailing list