mxcl / PromiseKit

Promises for Swift & ObjC.
MIT License
14.24k stars 1.46k forks source link

Issues with ending promise chains #561

Closed AttilaTheFun closed 8 years ago

AttilaTheFun commented 8 years ago

I've struggled with this issue for a while, and it has become more annoying in swift 3. I'm not sure if i'm doing something wrong, but i can't cleanly terminate chains of promises. Take, for example, a simple request to fetch a string from the server and print it to the terminal. I'd like to be able to do the following:

firstly {
    return URLSession.shared.dataTask(with: request).asString()
}.then { string in
    print(string)
}

However, the compiler warns me about the unused result from then, and often fails to infer that the last then closure in the chain should return void. It insists I either return an AnyPromise, or decorate my closure params with the (...) -> () in syntax which is awkward. I would like to propose adding a version of then that does not return anything called "finally" or something to mark the end of a chain of promises. Its closure could always return void to help the type inferencer along.

nathanhosselton commented 8 years ago

You're not handling errors. We think you should be, so we don't allow results to be discardable as our way of pushing developers to terminate all of their promise chains with acatch. Although you can also silence the warning by assigning the result to _. See also #548 #549. If you feel this is overbearing, discussion is welcome.

Also, we do have a "finally"! We call it always.

mxcl commented 8 years ago

Closing, dupes #551, #549, #548.

As said, discussion welcome.

AttilaTheFun commented 8 years ago

@nathanhosselton @mxcl I think the name always is confusing, as it's unclear whether it executes only when the chain of promises completes successfully, or if it fires regardless of whether the chain rejects or fulfills. I think firstly / finally as bookends of a promise chain make sense, and i believe in a previous promise kit release that was the case. I'm not sure what the motivation was behind renaming it. And I understand the motivation behind wanting people to handle errors, but often you really don't want to do anything with that error beyond maybe logging it. Maybe a compromise would be an alternative to catch, drop which just logs the error so you can cleanly and explicitly indicate that you don't care about the error. For example:

firstly {
    return URLSession.shared.dataTask(with: request).asString()
}.then { string in
    print(string)
}.drop()
mxcl commented 8 years ago

It executes if the promise rejects and it executes when it fulfills.

I considered something like drop, but it seemed to me:

_ = firstly {
    return URLSession.shared.dataTask(with: request).asString()
}.then { string in
    print(string)
}

Was more “swifty”.

finally was renamed because you could use it in the middle of a chain, and often would, and in such cases it seemed weird to name it finally. The original choice of finally was to mimic the @try, @catch, @finally system of objc.