As many of you are aware of, TC39 (the standards body around the JavaScript language) have a proposal for adding a new async primitive to the language called an "Observable". The current iteration of the spec has a ton of history outside of JavaScript, but tl;dr is most recently inspired by the RxJS library, which now is also updated as one unofficial reference implementation.
The usage of the term "observable" in regards to the TC39 proposal is incompatible with the usage by MobX, which means if TC39 does in fact ever include it in JavaScript it's probably highly confusing to use the term in this fashion.
Aside from future hypothetical awkwardness, historically I would argue a majority of people who _have_ heard the term associate it with either RxJS/Bacon/Most/or one of the other Reactive Extensions (Rx) implementations in other languages like Rx.NET, RxJava, etc. I feel like this may produce unnecessary confusion for adopters, especially if they wish to continue also using a library that implements their known definition of Observables, like RxJS, together with MobX.
I'd like to discuss possible alternative names MobX could adopt, if the MobX community is willing. I realize for some this is a non-trivial name change requiring a major version bump, but I believe it's best for the longevity of MobX.
FWIW MobX has a ton of overlapping functionality with Ember, which does not use the term Observable. Instead, they too use the terms computed properties and observers, but their computed properties also support writing/setting in a similar fashion of what MobX's @observable does.
Thoughts?
(for reference: Mobx vs Reactive Stream Libraries (RxJS, Bacon, etc))
Cc/ @blesh
Perhaps just @observe or @observed would be sufficiently different? I totally get why it was named observable.
Yep good point, @state or @tracked might also work (@observed vs @observer might be a too subtle difference for the quick reader). Doesn't have to be a breaking change but could also be an idiomatic alias with a decent deprecation message. (note to self: add traces to deprecation messages)
I like @tracked, because I feel like the words "observe" and "state" are already everywhere in my code. But that might just be me.
I also think that @state is confusing given existing usage in the React community. @tracked sounds good. I'll defer to the existing MobX community to bikeshed further. 😄
"trackables", trackable / extendTrackable / @tracked (or @trackable?) sounds like the best option to me so far. Any better ideas?
Alternatively: derivable (from DerivableJS). Or @mutable lol :)
I still like trackables
Track, watch, listen, subscribe, spy, guard, audit, peek, glue, monitor, hunt, crib, hook, stick, chase.
Hmm.. should observer be renamed to tracker or tracking in such cache? Or just reactive :see_no_evil:
Tracker. Reactive is a higher level concept.
I like @listen and @listener or @watch and @watcher. It's short and less verbose to type than @...able.
+1 @watch and @watcher
All those words are so generic and used in so many different libraries and contexts. Use the words that best describe what's happening and introduce namespacing if neccessary.
I am not a fan of "track", I feel like there is a subtle difference in the meaning, which doesn't fit into MobX context as good as "observe".
To me, the word "track" has some continuity in itself (in terms of time or space), while MobX is more about detecting and reacting to discrete state changes, not about following changes over time.
"Listener" is in fact quite similar to "observer", but "listenable" doesn't sound right and listeners are already widely used in the context of event programming.
"Watcher" is quite fine, but "watchable" only if it's enjoybale for watcher :) ...so I don't know about that either.
You've just accidentally introduced a new candidate: @detect (for
observable) + @react (for observer). 😎
Am Montag, 22. August 2016 schrieb urugator :
All those words are so generic and used in so many different libraries and
contexts. Use the words that best describe what's happening and introduce
namespacing if neccessary.I am not a fan of "track", I feel like there is a subtle difference in the
meaning, which doesn't fit into MobX context as good as "observe".
To me, the word "track" has some continuity in itself (in terms of time or
space), while MobX is more about detecting and reacting to discrete state
changes, not about following changes over time."Listener" is in fact quite similar to "observer", but "listenable"
doesn't sound right and listeners are already widely used in the context of
event programming."Watcher" is quite fine, but "watchable" only if it's enjoybale for
watcher :) ...so I don't know about that either.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/mobxjs/mobx/issues/470#issuecomment-241487376, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAdmqSVwoenjQzr6ptag50p16OpI3McUks5qidyKgaJpZM4JgwVW
.
@winterbe @detect is confusing because it can be used for observer, observer detects the changes of observable...
@detectable is better, but what does it mean that object is detectable? It doesn't make much sense...
What about:
@stateful
@stateAware
EDIT: when I think about it, @observer is only used on react components and in fact it's just autorun for component's render method, so... maybe @autorender or @autoupdate (react also uses the term "update")?
EDIT2: Yep, I really like @stateful and @autoupdate
I just found out this issue #169 and I am a little bit confused.
Aren't we saying "let's be compatible with TC39" and "let's change the nomenclature, because we are not compatible with TC39" at the same time?
@urugator there is a difference between having interoperability with TC39 observables and being TC39 observables.
For example suppose you create the following var x = mobx.observable({ y: 5 }). In principle there are two things that can be observed (with MobX.observe) here: x itself, and x.y. However introducing a subscribe method on either of them is trouble some, on x because it might collide with an actual property called subscribe, and you cannot introduce it on x.y either because it is a primitive and "cannot" have methods in the first place.
So the only thing that could safely be implemented is [Symbol.observable]() : Observable;, but that is only applicable to non-primitives: observable objects, arrays and maps. So the point of #169 is to do the latter, but also to provide a utility like asObservable(x, "y"): Observable. The bottom line being: not all mobx observables can be TC39 observables, although can all be converted to TC39 observables. It is a bit like the distinction between an iterable and an iterator.
@mweststrate I got the point, but I don't think that arguments are entirely valid:
Handling primitives:
let a = mobx.observable(5); boxed
let a = Observable.from(5); boxed
Handling structures:
let a = mobx.observable([1]); converted into observable
let a = Observable.from([1]); converted into observable
Handling object properties:
mobx.observe(x.y, onChange) not possible unless x.y is observable
x.y.subscribe(onChange) not possible unless x.y is observable
Only difference is the ability to observe specific property of observable object, which is something I would call a "parametrized subscription":
mobx.observe(x, "y", onChange)
x.subscribe("y", onChange) fictional alternative in the context of TC39
Even though we could call property y observable, we in fact still subscribe for observable x, the y can't be observed without being a property of observable x.
So the fact that y can't be subscribed does not go against the compatibility with TC39 observables, because y is not observable by itself.
What's more mobx.observe(x, "y", onChange) can still be done via mobx.observe(x, onChange), only the observed property must be filtered in onChange listener.
So the only real difference from x.subscribe(onChange) (aside from being static function) is that MobX provides a shorter and probably better optimized version for one special scenario.
If there is a concern that subscribe method might collide with actual property, shoudn't we be concerned the same way about overwriting [Symbol.observable]?
What if my object extending mobx.observable actually also implements TC39 observable?
I don't say that mobx.observable should implement Observable API, I just don't see incompatibilities, which would make it impossible.
@urugator hmm these are very interesting points indeed. Would it be confusing if an mobx.observable always contains a value, but if you subscribe to it, you won't get that values directly in your subscriber, but events? (like an array splice, just like observer). Probably that is ok.
@mweststrate Yea, the question is, what should be produced by observable for it's subscriber... the changed value (which is actually observable itself) or change event?
I would go for events, because they're more descriptive and versatile.
The mobx.observe basically produces events even now, because it never produces just a single value (even though the "event" is flattened into arguments).
However I don't know how practical it is. I think we need to ask why and in which way mobx should be compatible with TC39 Observables?
How we would like to use mobx in the context of RxJS or similar framework.
Is it even the same thing (TC39 compatibility and intended usage as observable)?
What are the benefits and real use case scenarios?
I haven't use any of these "reactive" frameworks yet, so I really don't have that kind of thinking "It would be cool if I could do this..."
My additional thoughts/opinions:
@mobx.observable shouldn't implement Observable API by itself, let the client do it when needed
@mobx.observable shouldn't implement [Symbol.Observable], let the client do it when needed
Provide:
mobx.subscribe(
observable: mobx.Observable
onNext : Function, // accepting single arg mobx.ChangeEvent
onError? : Function,
onComplete? : Function) : Subscription;
Provide:
@mobx.tc39.observable and mobx.tc39.observable(object) adding mobx.observable behavior alongside with:
subscribe(onNext, onError, onComplete) {
return mobx.subscribe(this, onNext, onError, onComplete);
}
[Symbol.Observable]() {
return this;
}
(Similary, anyone can easily implement decorator passing just changed value instead of ChangeEvent)
Provide:
mobx.Symbol.Observable available on any mobx.observable object as
[mobx.Symbol.Observable]() {
return this;
}
Refactor:
mobx.observable(object) so that it first checks for a presence of [mobx.Symbol.Observable] property on a passed object and if present, returns the result of [mobx.Symbol.Observable]() mimicking Obervable.from(object) behavior.
(maybe we could also provide mobx.from(object) and mobx.tc39.from(object) mimicking TC39 even better)
solves #492
Although I understand that some confusion might arise from using a similar term to the tc39 proposal, I think will cause to much confusion to rename the whole concept at this point. Especially since in practice this doesn't seem to lead to trouble very frequently. I usually explain it as: there are observable streams which emit events to which one can subscribe, like RxJs, and there are observable values from which we can observe the updates (MobX).
For the interoperability question, see #677
Most helpful comment
I also think that
@stateis confusing given existing usage in the React community.@trackedsounds good. I'll defer to the existing MobX community to bikeshed further. 😄