Chris
Chris

Reputation: 941

Incorrect try/catch behavior in Xcode 7 beta 3's Swift 2?

I have a problem with some Swift 2 code, compiled using Xcode 7 beta 3.

I have a class (see below) that has an initializer that takes a function, f, which can throw. If f does not throw, then a member variable (self.result) should be set to an instance of an enum that wraps the value that f returns. If f does throw, then self.result should be set to an instance of the enum that indicates the value is absent. At the end of the initializer, self.result should not be nil. I have checked the case where the f does not throw, and the behavior is correct. However, in the case that f does throw, self.result is nil at the end of the initializer (the assert is triggered). If I single-step in the debugger, I see that self.result seems to instantaneously be set and then flashes back to being nil.

(Note: You might suggest I represent the absence of a result as nil, rather than wrapping in the enum. However, I need to model the scenario in which the result of f has not been computed yet, has been computed successfully, or an attemopt has been made to compute the result but it has failed. Hence the enum.)

Have I misunderstood how Swift 2's error handling works? Or, is the compiler/debugger etc. behaving incorrectly?

Thanks in advance.

internal enum Result<T> {
  case Value(T)
  case None
}

public final class MyClass<T> {

  internal var result: Result<T>? = nil

  private init(f: () throws -> T) {
    let queueName = “some.string”
    let queue = dispatch_queue_create(queueName, DISPATCH_QUEUE_CONCURRENT)
    dispatch_async(queue) {
      do {
        let value = try f()
        self.result = .Value(value)
      }
      catch {
        self.result = .None
      }
      assert(self.result != nil, "Result must have value before block returns.")
    }
  }
}

Upvotes: 2

Views: 99

Answers (1)

Martin R
Martin R

Reputation: 539815

In

self.result = .None

the left-hand side is an optional Result, therefore .None on the right-hand side is inferred as Optional.None, and the statement is equivalent to

self.result = nil

What you probably meant is

self.result = Result.None

and then the assertion does not fail anymore. Alternatively, use a different enumeration value, e.g. case NoValue in your custom type.

Upvotes: 5

Related Questions