[swift-evolution] [Pitch] Guarding on enum values

Andrew Duncan andrewzboard at gmail.com
Tue Dec 22 22:58:46 CST 2015


Motivation

The guard statement rescues us from the pyramid of doom, and lets our code hug the left margin more... if the failure case is false or nil. I'd like to guard against specific values in an enum, and get the same flattening of code flow. This generalizes Swift’s convenient handling of Optionals. (I have a hazy perception that this was mooted for 1.x, but can’t remember where I read it.)

The goal is to make error-handling by result-returning smoother. (I need say no more about side-effect NSError** parameters.) Consider everyone’s favorite enum example: 

    enum Result { 
    case .Fail(String)      // Error message
    case .Succeed(MyType)   // Something we use.
    }
    
The Pitch (to avoid TL;DR)

I'd like to use something like this:

    guard case let .Succeed(m) = returnsResult() else {
         return it
    }
    // Can safely use m, otherwise Result is passed back the call stack.

Remarks

When I'm getting back a returned Result I want to bail immediately and propagate (return) the .Fail value, but to use the Succeed value. On the left margin, not in a welter of braces. The naive way, which at least has the value of directness, is:

    let r = returnsResult()
    let m:MyType
    switch r {
    case .OK(let dummy): m = dummy
    default: return r
    }
    // Can use m safely here.
    
This is bulky and leaves the value r cluttering the rest of the method. Not to mention the terrible hanging right-brace.

We can do better:

    let r = returnsResult()
    guard case let .Succeed(m) = r else { 
        return r 
    }
    // m may safely graze. 
    // r is mentioned *three* times, and is still hanging around.

Finally we see the gold of El Dorado:

    guard case let .Succeed(m) = returnsResult() else {
         return it
    }
    // m is in scope, no other cruft.

No repeated identifiers, no leftover debris.


More information about the swift-evolution mailing list