Do you have any plans to provide a property or method on the Variable class to allow directly accessing the latest value or is there currently a mechanism for doing so? I notice in the tests that you access the latest value as follows:
var latestValue: Int?
let subscription = c >- subscribeNext { next in
latestValue = next
}
I am new to Rx, however it seems it would be useful to supply a latestValue/value property on the Variable to simplify cases in which one desires access to the value without having to subscribe. Even a read only property would prove helpful. The subscription just feels like an extra hoop to jump through. Though I do understand if directly accessing the variable is an undesirable breaking with Rx concepts.
Or does "subscribeNext" always send the latest or "last" value?
Hi, @carlosypunto has asked me the same thing over email. I'm just going to paste you edited correspondence with him here :)
Variable doesn’t have any property called snapshot or value because that’s conceptually wrong thing to do in general case. But unfortunately could be perfectly normal and practical in most cases. I was totally torn by this decision and I will create documentation about this.
So why was variable named Variable then. It was named that way to make it explicit that it’s hot observable (everybody understand that variables are stateful). That means that variable Observable will originally contain cached last value that will be replayed to subscribers immediately on subscription (replay subject). This is not a general property of Observables.
These are the reasons why it's like this now:
But on the other hand:
Right now, what I'm planning to do is to add RxExperimental project that will contain that feature. In that way new users will be able to use it and won't need to define it themselves, but it will be clearly marked and documented as experimental for now.
I'm still torn by this decision, and it is unclear what should be the correct thing to do.
Why is pulling value a bad thing in general case?
In general case it’s wrong because you could have code like this (and this is a common anti pattern I've seen in multithreaded programs)
let v = Variable<Int>(0)
v >- subscribeNext { println($0) }
dispatch_async(queue1) {
v.next(v.value + 1)
}
dispatch_async(queue2) {
v.next(v.value + 1)
}
We can’t know what will be printed.
It could be 0, 1, 2 or 0, 1, 1
This maybe looks like a silly reason, and if this was a framework for UI layer only I would add it in a heartbeat, but one of the most common scenarios where people (and myself) will use this framework are multithreaded systems.
In that context, this is poison served as remedy.
That being said, that doesn’t mean you can’t make your code more elegant.
This is approx what I'm thinking of adding to RxExperimental project
extension Variable {
// because this is a snapshot of a value in time
var snapshot : T? {
get {
var snapshot: T? = nil
// This will make sure that you access variable in a thread safe manner
// Remember, if the value is complex, like array, you must ensure that only one thread is accessing the object at a time
// otherwise your program will crash.
// The performance penalty for this will probably be negligible if used a real app
self >- subscribeNext {
snapshot = $0
} >- scopedDispose
return snapshot
}
}
}
The other possible interface I'm thinking about is
variable.mutate { oldValue in
return // ….
}
but still unsure, maybe I'll add two of them to experimental project.
Would adding experimental project help or do you think that's a bad idea?
Do you have some other suggestion, please let me know.
As far as possible it should be clear that it leaves the original Rx philosophy. I´m newbie, I appreciate this type of aid. But my intention is to use the library as should be done, although initially for a easier approach I see useful see the experimental project
Thanks for the detailed explanation. I would much rather improve my thinking and continue learning the Rx philosophy than see the framework compromised by shortcuts that further compromise learning and understanding while enabling bad habits.
I'll port BehaviorSubject in next release, it has the necessary functionality that is similar to what you were asking.
The arguments are still valid, so be careful when to use it. It should be fine to use it in the UI layer.
Most helpful comment
Hi, @carlosypunto has asked me the same thing over email. I'm just going to paste you edited correspondence with him here :)
Variable doesn’t have any property called snapshot or value because that’s conceptually wrong thing to do in general case. But unfortunately could be perfectly normal and practical in most cases. I was totally torn by this decision and I will create documentation about this.
So why was variable named Variable then. It was named that way to make it explicit that it’s hot observable (everybody understand that variables are stateful). That means that variable Observable will originally contain cached last value that will be replayed to subscribers immediately on subscription (replay subject). This is not a general property of Observables.
These are the reasons why it's like this now:
But on the other hand:
Right now, what I'm planning to do is to add RxExperimental project that will contain that feature. In that way new users will be able to use it and won't need to define it themselves, but it will be clearly marked and documented as experimental for now.
I'm still torn by this decision, and it is unclear what should be the correct thing to do.
Why is pulling value a bad thing in general case?
In general case it’s wrong because you could have code like this (and this is a common anti pattern I've seen in multithreaded programs)
We can’t know what will be printed.
It could be 0, 1, 2 or 0, 1, 1
This maybe looks like a silly reason, and if this was a framework for UI layer only I would add it in a heartbeat, but one of the most common scenarios where people (and myself) will use this framework are multithreaded systems.
In that context, this is poison served as remedy.
That being said, that doesn’t mean you can’t make your code more elegant.
This is approx what I'm thinking of adding to RxExperimental project
The other possible interface I'm thinking about is
but still unsure, maybe I'll add two of them to experimental project.