RxSwift: Cannot flatMap a Single trait to a Completable trait
⚠️ If you don’t have something to report in the following format, it will probably be easier and faster to ask in the slack channel first. ⚠️
⚠️ Please take you time to fill in the fields below. If we aren’t provided with this basic information about your issue we probably won’t be able to help you and there won’t be much we can do except to close the issue 😦 ⚠️
If you still want to report issue, please delete above statements before submitting an issue.
Short description of the issue:
Cannot flatMap a Single
trait to a Completable
trait
Expected outcome:
I expect that the flatMap would let me convert to a Completable trait like in the example below.
What actually happens:
I get the following error:
'flatMap' produces 'PrimitiveSequence<SingleTrait, R>', not the expected contextual result type 'PrimitiveSequence<SingleTrait, _>'
Self contained code example that reproduces the issue:
func convertExample() -> Completable {
return Single<String>.create { single in
single(.success("hello"))
return Disposables.create()
}
.flatMap({ _ -> Completable in
return Completable.empty()
})
}
RxSwift/RxCocoa/RxBlocking/RxTest version/commit
v3.4.0
Platform/Environment
- iOS
- macOS
- tvOS
- watchOS
- playgrounds
How easy is to reproduce? (chances of successful reproduce after running the self contained code)
- easy, 100% repro
- sometimes, 10%-100%
- hard, 2% - 10%
- extremely hard, %0 - 2%
Xcode version:
8.3.1
⚠️ Fields below are optional for general issues or in case those questions aren’t related to your issue, but filling them out will increase the chances of getting your issue resolved. ⚠️
Installation method:
- CocoaPods
- Carthage
- Git submodules
I have multiple versions of Xcode installed: (so we can know if this is a potential cause of your issue)
- yes (which ones)
- no
Level of RxSwift knowledge: (this is so we can understand your level of knowledge and formulate the response in an appropriate manner)
- just starting
- I have a small code base
- I have a significant code base
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 3
- Comments: 35 (13 by maintainers)
I absolutely agree with @tarunon. I encounter that situation almost every day.
Currently I implement that architecture by this way,
Looks terrible. 🙃
If I can write
Looks smart. 😎
Single
should be able to be converted intoMaybe
andCompletable
, andCompletable
only toMaybe
(But Maybe cannot be converted to other traits).I wrote a code something like below and it’s working. It takes out the source observable once by
asObservable
and then convert it to other traits.I’ve thought about this a bit, we can do something similar like RxJava did, it makes sense, but it might take a month or two to release it.
In my opinion, that make sense next
flatMap
overloading.(T) -> Single<U>
(T) -> Maybe<U>
(T) -> Completable
Single<T>
Single<U>
Maybe<U>
Completable
Maybe<T>
Maybe<U>
Maybe<U>
Completable
※
Completable
has nonext
(success), so there is no implementation offlatMap
We often make the function that has 1 argument and return
Completable
, but if we wish to use this function inPrimitiveSequence
chaining, I think there is no way to use this function.andThen
can connect fromSingle
toCompletable
, but we cannot receivenext
(success) value.How do you think? @kzaher
Actually I believe that “flatmapCompletable” is totally necessary. In my case, I receive a stream from which I want to use data (Single), but the stream that goes next must not emit any value (Completable). Example:
I have been using RxJava2 and I think they manage better what is related to the changes between observable types than RxSwift… Single to Maybe, Single to Completable, flatmapCompletable, etc.
@freak4pc
What about, for example, network requests that yields just success or error? The
Completable
trait is the best representation of an operation that just completes or fails, although I recognize that the issue makingCompletable
s able to beflatMap
because of the main reason that they not produce anynext
event is understandable… Having network requests of Single<Void> really cringes me… I can’t see a correct approach to this, if someone does I’ll be grateful.Thanks for your opinion 😃
The only point I’d like to “point on” is that Completable has a contextual meaning.
Single means a Single element Maybe means a Single element or No Elements and Completable means No Elements
Completable is the “Correct” Rx terminology declared by ReactiveX, and the fact we have Never in swift doesn’t mean it needs to be hard to convert Observables to any kind of trait (be it Single, Maybe or Completable).
Using
Single<Void>
works just as well but when I read a protocol that says “Completable”, the mental load is much lower - I immediately understand contextually this means it would never return any values and can only fail or complete.Again, practically
Single<Void>
is the same, but contextually there is a slight difference.Anyways I completely respect your will to keep the library slim which is why I added it as an extension on my own codebase.
Thanks for the kind explanation, as usual 😃
I also stumbled upon a similar issue: I have a bunch on Completable methods and I would like to chain them in a sane way. However, it seems that it is not possible at the moment.
Actually, you can just call
.asObservable
on the Single and then flatmap it to an Observable.@HayTran94 Actually, we can write something slightly better:
Compiles fine on my machine.
@freak4pc I think the only
discoverability
part might be non optimal. I think as far as readability is concerned, it does exactly what name suggests as far as I can tell.If a sequence is a
Single
orMaybe
that proves that it has 1 and 0-1 elements respectively. That means that some operator would need to be performed on it to ignore the elements to make itCompletable
(which means that sequence doesn’t contain any element).We’ve added
asSingle
because there isn’t a way to prove compile time from type description ofObservable
sequence that it contains just one element, so we error outSingle
when it doesn’t contain exactly one element.In case of
Completable
we can prove compile time thatObservable
sequence doesn’t contain any elements (typedNever
). In case it can return elements, there is an operator that ignores all of the elements and returnsCompletable
.Like
RxJava
,Completable
hasandThen
operator if chaining is wanted.So far I haven’t encountered any situation where using
Completable
is advantageous toSingle<()>
, so I wouldn’t like to bloat the library with a lot of additional operators.I think this should work at this moment.
If this was modeled as
Single
.a bit cleaner.
The
ignoreElements()
comment from @kzaher seems right, except perhaps we don’t want to change the existing api. I just hacked up the following extension usingignoreElements()
and the existingasCompletable()
that’s already implemented forObservable<Never>
@programmerdave However, it handles server errors nicely.
materialize
also wraps the Error into a normal next event so your pipe doesn’t burst when the server emits an error. Very nice…