10

I need to use my own custom error enum in tasks that I create:

enum MyError: Error {
 case someError
}

var myTask: Task<MyModel, MyError> = Task { () throws -> MyModel in
            // in case of an error: 
            // throw .someError
            // ... perform some work
            return MyModel()
        }

but I got the following error at the beginning of Task initializer: Referencing initializer 'init(priority:operation:)' on 'Task' requires the types 'MyError' and 'Error' be equivalent.

How can I restrict the Task to only throw errors that are of my custom error type MyError ?

JAHelia
  • 6,934
  • 17
  • 74
  • 134

1 Answers1

13

Omit the unnecessary type declaration:

var myTask = Task { () throws -> MyModel in
    // in case of an error:
    throw MyError.someError
    // ... perform some work
    return MyModel()
}

The compiler implicitly (and rightly) types myTask as a Task<MyModel, Error>. The compiler doesn't care that what you throw is a MyError, because that's a form of Error.


Okay, I see now that the issue is merely that you asked the wrong question. You want to know why you can't declare this Task as a Task<MyModel,MyError>.

The reason is because of how this initializer is declared:

extension Task where Failure == Error {
    public init(priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success)
}

Do you see? This initializer is available only where Failure == Error. That's ==, not :. Using this initializer doesn't require that the Failure type be an Error, it requires that it be Error.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    I know that I can use it this way, but the error enums in my app are numerous as well the created tasks, I need a way to statically tell the compiler that a specific task should only throw `MyError` but not any other type of `Error`. – JAHelia Aug 17 '21 at 13:50
  • If you know the answer, why are you asking the question? – matt Aug 17 '21 at 13:54
  • OK, wait, I see the problem: you've asked the wrong question. I'll answer the question you _should_ have asked. – matt Aug 17 '21 at 13:55
  • thanks for the answer, I've edited the question text a little bit to be clearer – JAHelia Aug 18 '21 at 05:29
  • 1
    Well, as for "How can I restrict the Task to only throw errors that are of my custom error type MyError", you can't. But that's no big surprise. An ordinary `throws` function declaration cannot specify what type of thing it throws. – matt Aug 18 '21 at 11:05
  • 1
    Unfortunately this is so true at least until up this moment of time. Well, this is where `Combine` shines when I declare something like: `func getData() -> AnyPublisher` then my code is forced to only emit `MyError` errors. – JAHelia Aug 22 '21 at 07:02
  • 1
    You can certainly write code that forces itself to emit only MyError errors! If your question is how to do that, ask a new question asking that. But the point is, you cannot use the Task generic Failure type as your way of doing it. If you think this is wrong, file a bug with Apple. – matt Aug 22 '21 at 13:11
  • 1
    I'm (also) surprised that `Task`, unlike `Result`, does not support a `Failure` that is `some Error` rather than just `any Error` or `Never`. This seems like it would fit well with the existing API and could be provided with a `Task.init(_ priority: TaskPriority = nil, task: () -> Result)` initialiser, I think? It would support typed Failure in the way `Result` does. – Benjohn Dec 09 '22 at 13:13