[Pitch] withDeadline

How would deadline handling be tested? ie. if the system under test uses withDeadline , how can the deadline be tested, without waiting? With the previous pitch that was generic over Clock, it would be possible to pass in a fake clock, but that’s not possible now.

Go has an ingenious solution to this, with co-operation between the synctest package and the time package.

Time, in contrast, does only one thing: It moves forward. Tests need to control the rate at which time progresses, but a timer scheduled to fire ten seconds in the future should always fire ten (possibly fake) seconds in the future.

synctest can create ‘bubbles’ where time stands still, and can be advanced by time.Sleep. Would something similar be possible in Swift? Would structured concurrency make this easier, because child tasks have to complete before parents? It looks like Trio has a similar-looking testing option.


Having DeadlineError take the wrapped error as a generic parameter means it’s not possible to catch the error if the type is unknown. This was noted in the earlier pitch thread. Maybe DeadlineError<T> needs a DeadlineErrorProtocol (swiftFiddle) that would allow it to be caught without knowing the type of the underlying error?

public func downloadData() async throws {
  do {
    try await withDeadline(...) {
       // Previous code
    }
  catch let deadlineError as DeadlineErrorProtocol {
    switch deadlineError.cause { ... }
  }
 }

Similarly, what is the expected pattern for passing the underlying error back to callers, if there’s no distinction between causes (as shown in one of the examples):

do {
  return try await withDeadline(deadline) {
    try await fetchPreferences()
  }
} catch {
  throw error.underlyingError
}

Should there be an API that exposes this behaviour directly?

return try await withDeadlineButNoDeadlineError(deadline) {
  try await fetchPreferences()
}

Trio has the distinction between fail_at and move_on_at, which seems similar to this.


There are a few things that look like they were missed in the changes since the first pitch:

  • The first example has the nested errors as enum associated values, not the new underlyingError
  • The description for DeadlineError still mentions ‘the clock used for time measurement’
4 Likes