Swift 2: throwing errors in computed properties

To indicate that a function or method can throw an error, we write the

throws
keyword in its declaration.


How would we indicate this for computed properties. For example:



    public var isSuccess:  Bool {
        if let r = result {
            switch r {
                case .Success: return true
                case .Failure: return false
            }
        }
        else {
            throw FutureError.NotCompleted
        }
    }



According the documentation, it seems it is not (yet) implemented.


Possibly, it may read as this (does not compile):


    public var isSuccess throws:  Bool {
        if let r = result {
            switch r {
                case .Success: return true
                case .Failure: return false
            }
        }
        else {
            throw FutureError.NotCompleted
        }
    }



    public var isSuccess:  Bool { get throws {
        if let r = result {
            switch r {
                case .Success: return true
                case .Failure: return false
            }
        }
        else {
            throw FutureError.NotCompleted
        }}
    }

Can I ask why you'd want to? The above seems like a contrived example, and I can't figure out what the error is supposed to accomplish... Is it "NotCompleted" in the sense that there's an ongoing process, so it has neither succeeded nor failed yet? or "NotCompleted" in the sense that that part of the code isn't implemented yet?


If the former, then wouldn't an enum be a better return than a Bool? (case .Success, .Failure, .InProgress)

If the latter, you could just use an assertion.

Not trying to digress, just for clarification:

It's not a contrived example, it's actually code from a "Future & Promise" library, now trying to leverage error handling in Swift 2. So, you are right: this "thing", actually a "Future", is initialy neither in a Success nor in a Failure state - its "pending". It will be eventually completed with either a value or an error.


The reason why there is the property `isSuccess` is, because a "Future" type is akin to a `Result<T>` type (aka a `Try` in Scala). A `Result<T>` represents a result from some computation and may hold a value of type `T` or an error. And since `Result<T>` has properties `isSuccess` and `isFailure`, and `Future<T>` is akin to a Result - it has `isSuccess` and `isFailure` as well. Both return a `Bool` and I think it should throw if the future is not yet completed. Additionally, a `Future` also has `isCompleted` - which however does not throw. 😉

Keep in mind that in the Swift error handling architecture, a property can't [wouldn't be able to] throw and remain Obj-C compatible, because there's a secret extra parameter. This may not be an insoluble technical problem, but it kinda ruins the simplicty of the current error handling.


The other current limitation is that 'try' is limited in use in expressions. I wrote something like 'if x == try y ()' and I got a compiler message saying to put the 'try' part on the LHS instead of the RHS. Also, 'return try y ()' doesn't currently work, which is an irritation.

Fair enough. With that context, I'm still not sure that in Swift, an error is the right model for that scenario. Swift's error paradigm seems to be intended for actual run-time errors, as opposed to state modeling. What if instead of instead of Bool, you return a Bool? (ie: Optional Bool)? Then you effectively have a tri-state modeling of the API: true == .Success, false == .Failure, nil == .Incomplete.


Modeling isSuccess as a Bool? seems more intrinsically correct, since 'isSuccess' can be true, false, or neither, yet.

Karim, I'm not sure as well. The Future & Promise library is modeled after Scala's implementation. Scala somethimes throws an error in certain circumstances where it seems appropriate. Well, the API of this Swift library is not yet frozen. In the current API (Swift 1.2), there are no exceptions - for obvious reasons 😉.


But currently I'm trying to figure what could be the benefits leveraging error handling as provided in Swift 2. I would use throwing errors sparingly. However, in this case, this would be especially useful in computated properties. This Swift library would not have to have APIs that throws an error, though. The typically use case would utilize other APIs that won't throw. The `isSuccess` and `isFailure` for example is rather a miscellaneous API. A production code would rarely need to use these properties, but it might be useful for example in Unit Tests.

This isn't really good news. Albeit, I could accept that throwing properties are not allowed in Objc classes and subclasses - but could be allowed for computed properties in pure Swift classes and structs.


The other issues you mention could be just issues caused by feauters which are "not-yet-implemented" or caused by the early beta-state of the compiler - especially with respect to the error handling feature.


Anyway, IMHO, having throwing computed properties would be a big plus in designing architectures which leverages exceptions. The fact that exceptions are difficult to implement by a compiler vendor - well, this is pretty old and true as well. Consider C++: this language couldn't be more complex, and the same people developing Swift solved it for C++ anyhow, too 😉

There's other constraints too. In Swift, computed properties and stored properties should be compatible to change one for another in any time without broke the program.

Could you please give an example to illustrate the problem?

The Obj-C compatibility applies only to properties, not to methods in general. Swift's error handling requires a final 'error: (NSError**) outError' parameter in the corresponding Obj-C method, but merely hides that parameter on the Swift side. But it's "really" still there.


I'd also encourage you not to think of Swift error handling as "exceptions". It's not implemented that way, it just borrows the familiar try/catch syntax to use for its own non-exception error handling. That's part of the attraction.

"

I'd also encourage you not to think of Swift error handling as "exceptions". It's not implemented that way, it just borrows the familiar try/catch syntax to use for its own non-exception error handling. That's part of the attraction.

"


Thanks... that's what I was trying to say in my previous comment... just couldn't find the right words.

Yeah it is a problem I feel many don't want to get: Swift 2 has *NO* exceptions...

Well, it has exceptions via assert(), precondition(), explictly unwrapped optionals, etc... just not any exception handling.

Yeah I meant that. I have seen to many already trying to use Swift error handling as controlflow that it points out people don't understand that it isn't based on exceptions.

I certainly have a non-contrived example. Though perhaps I am using throw/try inappropriately in that I don't understand where I should be handling errors.

I have a getter for a member of a class that makes use of something that is ultimately calling something that incudes


static func getSecBytes(count: Int) throws -> [UInt8] {
  ...
   let res = SecRandomCopyBytes(kSecRandomDefault, count, bytePtr)
   guard res == 0 else { throw RandError.Oops }
  ...
}

(As you see, I've put a lot of thought into the cases for my ErrorTypes)


Now perhaps I should handle that error close to where it occured, but I wanted to be able to actually say something to the user and give her some other course of action.


getSecBytes() is called by "func randomInRange(lower: Int, upper: Int) throws -> Int"


That, in turn, is something that I would like to try in a getter:


var text: String {
  get {
       var result = ""
       do {
            result = onsets[try RandUtils.randomInRange(0, upper: onsets.count - 1)] 
            result += nuclei[try RandUtils.randomInRange(0, upper: nuclei.count - 1)]
            result += codas[try RandUtils.randomInRange(0, upper: codas.count - 1)]
       } catch {
            print("text getter in Syllables caught an error it can't throw")
            assert(false)
       }
       return result
  }
}


To get this to compile I've had to catch and handle (after a fashion) the error in this getter, which is really the worst place to handle it. While I might be misguided in wanting to throw this way up toward the UI, that is certainly better than trying to handle this here.


I could do this the old fashioned way of making text and optional and returning nil. But I thought that one of the goals throw/try/catch was so that we would stop using nil as an error indicator.

Swift 2: throwing errors in computed properties
 
 
Q