Add AnyVariable (get-only Variable)#1118
Conversation
Generated by 🚫 danger |
There was a problem hiding this comment.
Hi @inamiy ,
Thnx for making this PR. I've seen quite a few of your projects, and it looks like you have similar interests :)
Unfortunately I don't think we should import this PR. I can definitely see how something like this could be useful
... which is highly useful when encapsulating Variable inside some view model, disallowing its binding from outside.
... but I don't think the core project should be optimized for MVVM pattern.
I think I'm probably to blame a bit for the Variablegate scandal. The reason why I've added Variable to RxSwift because finding BehaviorSubject is just excruciatingly hard and it was affecting adoption of this library.
After that people started to use it for MVVM, and I guess that made sense since we've added some additional guarantees, but I would like to stop there.
It's a tiny class that gives us pretty big bang for a buck by significantly helping new users but not deviating too much from cross platform implementation. And when one looks at its implementation, it's just a simple wrapper around BehaviorSubject, so there is another learning opportunity there.
I think it would maybe make more sense to add a new RxMVVM project to RxSwiftCommunity since there was already a request like this in the past.
My suggestion would be to create a unit named Value that has all of the Driver unit guarantees + additional guarantee that it will always emit a value synchronously upon subscription.
So one can convert Driver to Value by just applying startWith operator or directly from Variable to Value without any additional information.
| /// Unlike `BehaviorSubject` it can't terminate with error, and when variable is deallocated | ||
| /// it will complete it's observable sequence (`asObservable`). | ||
| public final class Variable<Element> { | ||
| public final class Variable<Element>: ObservableConvertibleType { |
There was a problem hiding this comment.
This is actually on purpose.
I didn't want somebody to write extension for ObservableConvertibleType and accidentally retain Variable.
Not conforming it to ObservableConvertibleType isn't perfect solution for that since anybody can make it conform, but it should reduce the chance a bit.
¯\_(ツ)_/¯
There was a problem hiding this comment.
I got your point, but I just wonder if ObservableConvertibleType will ever be a useful protocol for 3rd party users 😅
There was a problem hiding this comment.
Hi there, I'm interested that why Variable does not conform to ObservableConvertibleType and ObserverType.
In my opinion, I think that the type A that implemented ObservableConvertibleType make B as Observable and some other object should retain B object, not A object directly.
Then Variable case, the Observable is a internal BehaviorSubject so, Variable never be retained other object.
But now, maybe some of Observable family has ObservableConvertibleType directly. Can we change this?
There was a problem hiding this comment.
Hi @tarunon ,
the mere fact that we are relying on the fact will somebody retain variable or not means that this is fragile API (the part about completing variable observable sequence on deinit). That's why I don't like it.
It is pretty normal to create a reference to extension source, being it ObservableType or ObservableConvertibleType. This is being done all the time, and it shouldn't be a problem.
That's why Variable doesn't conform to ObservableConvertibleType, because that increases the chances of somebody retaining it.
Every solution has it's drawbacks.
There was a problem hiding this comment.
@tarunon
I'm assuming that observable.flatMap { _ in variableFromOuterScope } will be a beginner mistake that should be avoided.
BTW for ObserverType, I guess Variable can't conform to this protocol because of NoError restriction which protocol itself can't guarantee.
There was a problem hiding this comment.
Thanks for the discussion.
Finally, I can understand that why Variable doesn't conform to ObservableConvertibleType.
@inamiy
About ObserverType, I think that is not a real problem. For example, UIBindingObserver has a same implement that func bindTo(_ variable: Variable<E>) -> Disposable's one.
If my understanding is correct, adding ObserverConvertibleType may help us.
I think it is effective not only Variable.
There was a problem hiding this comment.
(Just for memo) Variable should not conform to ObserverType because terminal events will be ignored, i.e. variable.on(.completed)) then variable.on(.next(value)) will send value. (And using fatalError inside is not an option...)
|
I guess it could also make sense to add |
|
Hi @kzaher, thank you for mention :) If I understand correctly:
|
|
Hi @inamiy ,
I think it should be tied because it's a safer alternative. The only environment where that unit makes sense is a stateful one (like client app). Since Since
I don't think that in general dependency chain should be the only reason to decide how public API should look like. If that was the case then we should also make Because:
I think it would be more suitable to add it to
I don't think that it should have an API that allows access to its latest element, just that it should guarantee that initial value is always delivered immediately upon subscription. Having a |
|
@kzaher
BTW:
|
|
Hi @inamiy ,
Yep, got it :) I'm not trying to say is it useful or not, I'm trying to say that there are a lot more criteria that need to be satisfied for us to pull something in RxSwift project.
When I use term term cross platform, I'm not referring to iOS, macOS, tvOS, .... but to RxJS, RxJava, RxRust, RxGo ... Everything that is entering RxSwift core library should strive to be aligned with the core observable sequence interface/concept (observable sequence compatible), strive to follow cross platform implementations, have no external dependencies, promote declarative style, be useful enough for us to maintain it here (maintaining Swift code is not cheap), align with future plans (potentially adding It would be extremely easy and popular choice to add a lot of convenience extensions in there for us to maintain, but it's extremely hard to get them out or actually maintain them. |
|
@kzaher I would like to hear if anyone else is 👍 or 👎 to this PR. |
|
Ok, cool. |
|
FYI I open-sourced https://github.com/inamiy/RxProperty . |
This PR adds
AnyVariableas a get-onlyVariable, which is highly useful when encapsulatingVariableinside some view model, disallowing its binding from outside.This type is almost the same as ReactiveSwift's Property.