
Object.observe withdrawn from TC39 - smasher164
https://mail.mozilla.org/pipermail/es-discuss/2015-November/044684.html
======
pavlov
In my experience, observing individual properties on model objects just isn't
very useful in real world apps. Cocoa has long offered "key-value observing"
(KVO) for this purpose, but other mechanisms like notifications tend to be
more practical, usually because listeners need some context in order to do the
best thing in response to a change, and an individual property change won't
carry any of that context.

Here's a practical example... Imagine an editor where an on-screen element is
deleted. The controller might do a bunch of stuff such as:

    
    
      element.parent = nil
      scene.clearReferencesToElement(element)
      container.delete(element)
      self.selection = []
    

If there's a listener on "container", it will get notified even before the
selection was cleared. That's probably not the intention.

If we know that's going to happen, we could move the selection manipulation
before the container access... But then we have fragile code that depends on
implicit behavior in a model class. Always better to send an explicit event.

~~~
tolmasky
I now subscribe to the React-style "wait, why are you listening to anything?"
mindset. However, if you're going to go down the mutable path, I think KVO was
particularly well designed.

The main reason was that it made composition pretty sane and created clear
places to handle changes. With KVO, you implement your KVO-compliant mutation
methods, and all changes would then get funneled through there (most notable
container ones). Compare the mess that is NSView
(addSubview/insertSubview:positioned:relativeTo:/removeFromSuperview/etc) to
the post-KVO NSTreeNode. NSTreeNode simply exposes .mutableChildNodes, which
you treat as a normal array (addObject:/etc) and after adding a child, it then
has parentNode set to the parent after. This was great for lots of reasons: 1.
No need to re-create API, you just used NSMutableArray's existing API. So
[someNode.mutableChildNodes removeObjectsWithPredicate:somePredicate] and all
the parentNode relationships get handled for free. Compare this to pre-KVO
methods where every time you wanted to take advantage of a neat NSMutableArray
feature, you'd have to re-expose it yourself like
removeSubviewsWithPredicate:, or wind up having to copy out the array, mutate,
then re-assign with setSubviews: 2. Less room for error since all your cleanup
code just happens in removeObjectFrom<Key>AtIndex:, one funnel.

Again, I believe this to be a great local maxima for this style of
programming, one that was never that fully explored since the move to more
KVO-ness was eclipsed by the attention to iOS. I think most the problems are
better solved through React's top-down approach.

~~~
haberman
I like the React model, but it does make one key assumption. It assumes that
DOM mutation is so slow that re-rendering and diffing the entire virtual DOM
for every update is basically free in comparison. I like the simplicity of
React's approach, but this assumption makes me a little uncomfortable.

~~~
Silhouette
As an anecdotal data point, that assumption survived approximately no time at
all during a recent exercise I was involved with evaluating how to build a new
and reasonably large web app. With similar scepticism but trying to keep an
open mind, we did an experiment allowing the entire DOM to rerender from a
top-level React component when the underlying data model changed. It performed
pretty much as badly as everyone thought it obviously would.

We then switched to exploring more standard approaches like having individual
components monitor the relevant model events and manage their own state, using
React's rendering model at a much finer granularity. We haven't finished our
investigations yet and there are some other concerns about React's performance
under certain conditions, but so far, the finer-grained approach seems more
promising and is our most likely way forward for this particular project.

~~~
Akkuma
Was your data mutable or immutable? The former requires you to write
shouldComponentUpdate logic that isn't just old == new. If you didn't write
any of that logic and didn't use immutable data rendering everything again
from the top down due to a single change is of course going to be terrible
performance.

If you wanted to be more adventurous you should look at alternative virtual
dom implementations [http://vdom-benchmark.github.io/vdom-
benchmark/](http://vdom-benchmark.github.io/vdom-benchmark/). What you'll find
is that React is actually the slowest one out there based on performance. For
instance, on dbmonster InfernoJS sees 50-100% more fps and on my machine ~20x
better benchmark performance. If you want the next popular implementations
look at virtual-dom, which is leveraged in a variety of frameworks like
[https://github.com/ashaffer/vdux](https://github.com/ashaffer/vdux), or
Google's Incremental DOM, [https://github.com/google/incremental-
dom](https://github.com/google/incremental-dom).

~~~
Silhouette
We've also found that some of the other virtual DOM implementations that are
popping up can be somewhat faster than React's, though I confess I can't
remember exactly which ones as I write this.

But I don't think that really matters. Fundamentally, once we have a
moderately complicated data model such as configuring a few thousand entities
of perhaps 50-100 different types with assorted properties each and assorted
constraints between them, even a relatively passive scan over the model to
rerender the UI from the top following each transaction on the data model does
not appear to be a viable architecture today.

Fortunately, that architecture is also unnecessary, as a modest amount of
finer-grained integration work presents a much more realistic alternative. The
declarative style of specifying a UI still has considerable potential as a way
of composing manageable components, we just need a scalable way of decomposing
the overall design to match, and it seems for now that means smaller-scale
components need to be aware of their own concerns in some cases.

------
noelwelsh
In my opinion this is a good move. As the post notes, the JS world is moving
away from the side-effect heavy code that motivates Object.observer. JS
doesn't need any more legacy mistakes enshrined in the language spec, and
without an overwhelming need for this it should not be adopted.

~~~
Silhouette
_As the post notes, the JS world is moving away from the side-effect heavy
code that motivates Object.observer._

It may well be that Object.observer was the wrong level of granularity, and I
agree that language specs should evolve cautiously.

That said, I think it is far too early to make generalisations as broad your
statement above. React-style development is still a _tiny_ fraction of overall
web development, and React itself isn't even at version 1.0 yet and IMHO still
has significant fundamental architectural concerns that haven't been fully
explored yet. It promotes some interesting ideas, and I'm glad someone with
the profile of Facebook is challenging assumptions, but in turn reasonable
people could challenge a lot of the ideas coming out of the React team and
we're still far from understanding the long-term trade-offs of that style of
building for the web.

------
bcherny
Bummer. The latest web trend is immutability and event streams, but javascript
data structures are almost all mutable by default, and O.o is a great way to
take advantage of that fact. Instead of abstracting away data changes behind
events, why not use data directly? Instead of fighting the language, why not
(at times) embrace mutability?

~~~
msvan
Alternatively, why not embrace immutability and add native immutable data
structures to JS? I believe there is a TC39 proposal for this, in fact. Even
if O.o had become mainstream, I would've stayed away from it. The immutability
trend is not due to the impracticality of dealing with object observation, but
due to inherent issues with mutable state.

~~~
smasher164
Here's that proposal. [https://github.com/sebmarkbage/ecmascript-immutable-
data-str...](https://github.com/sebmarkbage/ecmascript-immutable-data-
structures)

~~~
bcherny
ha! i actually commented on this guy a few months ago. javascript is designed
in such a way that i think true, clojure-like immutable data structures are
not possible. we'd either need to overload comparators (===, ==) so that they
compare immutable data by value (rather than by reference, which is the case
for their mutable counterparts), or implement java-style .equals methods for
immutable objects (or as static methods on their constructors). neither seems
to be a great fit for javascript.

see my comment here [https://github.com/sebmarkbage/ecmascript-immutable-data-
str...](https://github.com/sebmarkbage/ecmascript-immutable-data-
structures/issues/4#issuecomment-99555565)

------
iamleppert
Sad about this. I think we still need a high performance way to observe
changes on objects without a lot of framework bloat.

~~~
lyschoening
There's still Proxy for that.

[https://developer.mozilla.org/en/docs/Web/JavaScript/Referen...](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy)

~~~
toomim
Indeed, Proxy always seemed like the more general version of Object.observe.
It not only "tells you when state changes", but lets you write code to say
what that means.

What's the state of Proxy? Are the people behind it still working on it? Are
we going to be able to use it? Will it be fast?

~~~
thomasfoster96
Proxy has already been standardised (in ES6) so it should be coming into
browsers soon. It's a little harder to polyfill than O.o though.

~~~
AnkhMorporkian
As far as I know Proxy is impossible to polyfill. There are some patches which
make old browser versions of Proxy meet the spec, but I just don't think you
can close the Proxy gap with pure javascript.

~~~
pipeep
It's possible if you also translate all of the code that uses the polyfilled
object by converting every MemberExpression to a function call, but that's
probably a nightmare for performance.

~~~
bcherny
what happens when i add a property to the object that i'm proxying after the
Proxy is already instantiated? you wouldn't be able to detect the addition and
add getters/setters for the property unless you use some sort of O.o or dirty
checking on the underlying object.

see
[https://github.com/bcherny/auditable](https://github.com/bcherny/auditable)
for an implementation, sans O.o.

~~~
pipeep
If you intercept _every_ MemberExpression on _every_ object, you can solve
this (with the exception of eval), but as I said, it would be incredibly slow.

------
z3t4
We still have Object.defineProperty (ES5) where you can have functions for get
and set. I use this for database ORM for native Node.js object persistence.

------
filoeleven
What are the implications of this for Angular 2.0? Aren't they basically
relying on this feature to make the framework efficient? Or was that just for
improving Angular 1.x?

~~~
Bahamut
Angular 2 is using observables via
[https://github.com/reactivex/rx.js](https://github.com/reactivex/rx.js)

~~~
skeoh
Your link 404s.
[https://github.com/ReactiveX/RxJS](https://github.com/ReactiveX/RxJS)

~~~
Bahamut
Oops - sorry about that, typed that on a phone

------
dccoolgai
I hope they keep it in V8, if only for debugging. There are some cases where
this is the only practical way to see what is mucking with your object and
when. If they take it out of the spec, it would be nice if they could add it
as a method to console or something, at least.

~~~
lemevi
Consider using a `Proxy` object.

[https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)

~~~
AnkhMorporkian
Proxies are brilliant. I used one to create an promise based RPC system that
allows you to call any method you want.

So before proxies, we used to do it as:

    
    
        await server.rpc.run("methodName", [argumentOne, argumentTwo])
    

Now, we just do:

    
    
        await server.rpc.methodName(one, two)
    

The proxy traps that method call and returns a promise that runs that on the
server. It's very slick and has made our code a lot more readable.

------
acbabis
I understand wanting to discourage directly mutating Objects, but I wish we
knew what was going to replace O.o. IMO, we should have access to something
like NodeJS' EventEmitter in the browser natively.

~~~
gavargas08
[https://github.com/zenparsing/es-
observable](https://github.com/zenparsing/es-observable)

------
nevir
I think the main thing that hamstrung Object.observe was that observations
were asynchronous (scheduled as a microtask). It made data flow very difficult
to follow for developers (particularly when driven by data binding systems).

------
wereHamster
This is unfortunate. I used O.o to implement type-safe lenses in my TypeScript
project
([https://github.com/wereHamster/avers](https://github.com/wereHamster/avers)).
I always cringe when I see Immutable.js
`c.setIn(['some','deeply','nested','field'], x)`, so much opportunity for
typos, and no support for refactoring.

For a while now I wanted to use proxies, but they are only supported in
Firefox, and no timeline when they get to Chrome. I'll have to see what I can
use as replacement.

------
paulftw
So they expected major frameworks to switch to an unfinished spec without a
clear ETA for approval and that didn't work out?

I think this is a major blow to web performance. We are bound to perform
O(every object on page) computations on every event, instead of O(tiny bit
that's actually changed). This is how having a device with gigs of RAM, close
to ghz CPU we still measure FPS of a page with one table and 5 images

------
aikah
> and hope to remove support from V8 by the end of the year (the feature is
> used on 0.0169% of Chrome pageviews, according to chromestatus.com).

I hope nobody uses that stuff in production ... even if there are polyfills,
their performances are nowhere near the performances of the native
implementation.

> After much discussion with the parties involved

Would be interesting to know the content of these discussion.

~~~
vcarl
Anyone using it in production shouldn't have, it's completely unsupported
except by Chrome and Opera.

[http://caniuse.com/#feat=object-observe](http://caniuse.com/#feat=object-
observe)

~~~
Touche
It's supported in Node.js.

------
michaelsbradley
Any implications for Google Polymer? I haven't kept up, but I remember from
the time that I was working with it, Polymer depended on (i.e. built upon)
either a native implementation of Object.observe or a polyfill that performs
"dirty checking". The latter is not exactly a high performance underpinning
for a library (though it works, sure).

~~~
bsimpson
From the letter:

> Polymer rewrote from the ground up for its 1.0 release, and in that
> rebuilding did not utilize O.o

~~~
michaelsbradley
Ah, thanks... I read the headline, glanced quickly at the link and typed up my
polymer-related question as it came to mind. I should have actually read the
letter. :-)

------
PhrosTT
I know everybody loved this feature, but I was pretty scared of all the gross
code junior devs might have made with this.

~~~
ihsw
Junior devs? I could see this being yet another gross tool used by seasoned
and junior devs alike, with the former trying to be clever with over-
engineered solutions and the latter not knowing better.

------
JDDunn9
A sad day for Javascript. Why were only frameworks considered? Some of us
still prefer vanilla JS. Also, more options are better than fewer. This is
like saying, "Hammers have become quite popular lately, so we've cancelled
plans to make a screwdriver."

------
jjeswin
Believe that they might have withdrawn on performance backgrounds.

------
tjholowaychuk
Thank god.

------
andrewmcwatters
Object.observe in itself was a declaration that the web community at large is
not ready for serious software development yet.

Any seasoned developer would see the ignorance in implementing such a feature.

~~~
angersock
I used to work on a legacy Java codebase that made heavy (mis)use of the
Observable pattern, and I must second your sentiment.

Invariably a system acquires enough stuff going on that you get "observer
storms" of feedback, or people find really weird couplings that are not
immediately obvious because something several modules away is observing
something it doesn't need to.

~~~
acbabis
In order to observe an Observable object, you need to have a reference to it.
Adding an Observer to something that you shouldn't isn't possible without
introducing it as a dependency. If someone _does_ inject something so they can
observe it, it's easier to spot the coupling.

It sounds like the legacy code you got stuck maintaining put logic inside the
observers, which isn't the Observer Pattern's fault. In my own experience, not
using event patterns like the Observer Pattern is probably the biggest cause
of difficult-to-maintain code.

------
strictfp
The original web 1.0 where each state had an url and was rendered sequentially
from scratch was actually arguably much better than the stateful event-driven
UI mess we have now.

Moving from raw native ui frameworks very similar to todays js UI libs to HTML
pages was a big paradigm shift, but was IMO better for most standard apps.

I've been thinking for a long time that it would be a good idea to build a
client-side library where each state has an URL. Essentially just take the
classic backend view rendering technique and move it to the client. Could work
out really well I think. Event-driven techniques can then be reserved for
really interactive apps like games.

~~~
mindcrime
Classic example... I login to the EMR system my GP's office uses, and click
around a bit, looking at test results, notes, etc. Then, for whatever reason,
I happen to reload the page or click the "back" button. Boom, I'm out of the
application and have to login again from scratch. Grrrrr... SPA's and this
fancy stuff have their place, but let's not pretend that it doesn't come with
a cost.

~~~
cglace
You can have SPA's and the ability to reload and maintain application state.

