Thomvis/BrightFutures

Promise chaining in BrightFutures using flatMap

sonnykr opened this issue · 3 comments

I am trying to do something like this:

function1().flatMap { [weak self] resultOfFunction1 in
    self?.function2(resultOfFunction1)
}.onSuccess { resultOfFunction2 in
    doSomethingUseful(with: resultOfFunction2)
}

Since the self reference in flatMap for function1 is captured weak (weak self), the compiler throws me error. Usually I do

guard let strongSelf = self else { return nil }

but in this case, the return expects another future. How can this be solved? Seems like a bug (in either the library or it's missing documentation?)

It's a good idea to capture self weakly in the closure passed to flatMap, since it's executed asynchronously and it would extend the lifetime of self.

To solve your problem, you'll need to cover the case when self is gone inside your closure, so think about what the fallback is, if that is the case. (If you know for sure self cannot be released, you can consider using unowned instead of weak.) The way I would solve it is by returning a failed future when self is nil, so for example:

function1().flatMap { [weak self] resultOfFunction1 in
    self?.function2(resultOfFunction1) ?? Future(error: .illegalState)
}.onSuccess { resultOfFunction2 in
    doSomethingUseful(with: resultOfFunction2)
}

Hope this helps!

Yes returning another future with error state makes sense in this case. However, after doing something like this, I get Ambiguous use of 'flatMap' error

// This throws: Ambiguous use of 'flatMap' on line1

function1().flatMap { [weak self] resultOfFunction1 in
    guard let strongSelf = self else { return Future(error: .illegalState) }
    return strongSelf.function2(resultOfFunction1)
}.onSuccess { resultOfFunction2 in
    doSomethingUseful(with: resultOfFunction2)
}.onFailure { (error) in
    thatsNotGood(error)
}

same here:

// This throws: Ambiguous use of 'flatMap' on line1

function1().flatMap { [weak self] resultOfFunction1 in
    self?.doSomePrepworkForFunction2()
    return self?.function2(resultOfFunction1) ?? Future(error: .illegalState)
}.onSuccess { resultOfFunction2 in
    doSomethingUseful(with: resultOfFunction2)
}.onFailure { (error) in
    thatsNotGood(error)
}

but, this works:

function1().flatMap { [weak self] resultOfFunction1 in
    self?.function2(resultOfFunction1) ?? Future(error: .illegalState)
}.onSuccess { resultOfFunction2 in
    doSomethingUseful(with: resultOfFunction2)
}.onFailure { (error) in
    thatsNotGood(error)
}

Any idea what's going on here?

It's due to the Swift design doing type inference for multi-statement closures. type annotations, like -> Future<V,E>, can solve it for multi-statement.
c.f. https://bugs.swift.org/browse/SR-6042