Re: Object.observe feedback
native feature here. - Given the five solutions in my document, as the champion of Object.observe, what solution would you recommend someone use to process the records? Use a library? Keep a copy and just compare yourself? Your insight into how you expect this spec to be used would be appreciated. Thanks Rafael – again I love the standard. I may still be misunderstanding how this works. But you asked for feedback. Let me know your thoughts. Don P.S. – happy to add any of this to jsbin if you’d like to see it more closely with my testing scripts. *From:* Rafael Weinstein [mailto:rafa...@google.com] *Sent:* Sunday, February 16, 2014 8:06 AM *To:* Woodlock, Don (GE Healthcare) *Cc:* es-discuss@mozilla.org; dfwoodl...@gmail.com *Subject:* Re: Object.observe feedback BTW, here's your example using observe-js: http://jsbin.com/leh/1/edit On Sun, Feb 16, 2014 at 7:50 AM, Rafael Weinstein rafa...@google.com wrote: Hi Don, Thanks for the thoughtful feedback. I'm very glad you're excited about the feature. The short answer to your question is: the data you want is provided, but your processing needs to be more sophisticated. [BTW, The Chrome/V8 implementation (to the best of my knowledge) fully implements the latest spec for Object.observe] Basically, you're making an assumption about processing log data which is understandable, but unfortunately false. Though it would be nice, it's simply not possible to process each change record by looking at the final state of the observed object. Object.observe provides full information about the changes that occur, but depending on what view you want, you may need to do some processing to get the right answer. Based on the use-case you describe, it sounds like you have a very common desire -- to synchronize two objects, one of which has changed. The pattern requires what I'll call a diff in time view of the changes. In other words: from time 0 to time 1, what's the minimal set of changes I would need to apply to a copy of the observed object at time 0 in order to transform it into a copy of object at time 1? As you've found, Object.observe doesn't provide you this view of things. It provides you with a log of what happened along the way. However, you can use the log view as input into a transform which will provide you with the diff view. I've provided a JS library which serves multiple purposes: -A handy library for those who want the diff view of things -A reference implementation of some of these algorithms -A polyfill so that you may use this functionality in browsers that don't implement Object.observe (the polyfil mode has less desirable performance -- specifically the cost to determine what has changed is proportional to the total set of observed objects -- as opposed to Object.observe where the cost is proportional to the number of changes which took place). The library is here: https://github.com/Polymer/observe-js It may be sufficient for your use case (as well as act as the polyfill you were attempting to create) or it may simply serve as documentation for the processing that is required. Thanks again for your feedback and have fun. Cheers Rafael On Sun, Feb 16, 2014 at 5:25 AM, Woodlock, Don (GE Healthcare) don.woodl...@med.ge.com wrote: HI Rafael et al, I have some feedback into the Object.observe proposal. Now I may be missing something so any clarification or education would be appreciated as well. But I do love this particular spec and can’t wait to see it implemented. But while I was implementing a pseudo-polyfill of it for my own purposes, I noticed an ‘information hole’ in the ChangeRecords design. This is due to the asynchronous nature of the notification delivery and that subsequent mutations may have occurred by the time the notification is ‘delivered’. In particular I believe a new ‘added’ property is needed to the ChangeRecords of the splice transaction of an array mutation in the Array.observe design. Here’s the particular situation: First of all I’m assuming that the purpose of the ChangeRecords is to give the ChangeObserver enough information, beyond the fact that a change occurred, so that it doesn’t have to reprocess everything, but can be specific and efficient based on what in particular has changed. For example if I have a view that lists a bunch of students and it’s observing an array of students, if a student gets added to the array, I’d like to know enough so the view can just add the one student and doesn’t have to redisplay the entire list because it knows the array has changed somehow. Secondly I’ll assuming that the Chrome Canary implementation of Array.observe is suitably similar to the spec as that’s where I have been learning about what this design looks like in practice. Let’s say
Re: Object.observe feedback
Hi Don, Thanks for the thoughtful feedback. I'm very glad you're excited about the feature. The short answer to your question is: the data you want is provided, but your processing needs to be more sophisticated. [BTW, The Chrome/V8 implementation (to the best of my knowledge) fully implements the latest spec for Object.observe] Basically, you're making an assumption about processing log data which is understandable, but unfortunately false. Though it would be nice, it's simply not possible to process each change record by looking at the final state of the observed object. Object.observe provides full information about the changes that occur, but depending on what view you want, you may need to do some processing to get the right answer. Based on the use-case you describe, it sounds like you have a very common desire -- to synchronize two objects, one of which has changed. The pattern requires what I'll call a diff in time view of the changes. In other words: from time 0 to time 1, what's the minimal set of changes I would need to apply to a copy of the observed object at time 0 in order to transform it into a copy of object at time 1? As you've found, Object.observe doesn't provide you this view of things. It provides you with a log of what happened along the way. However, you can use the log view as input into a transform which will provide you with the diff view. I've provided a JS library which serves multiple purposes: -A handy library for those who want the diff view of things -A reference implementation of some of these algorithms -A polyfill so that you may use this functionality in browsers that don't implement Object.observe (the polyfil mode has less desirable performance -- specifically the cost to determine what has changed is proportional to the total set of observed objects -- as opposed to Object.observe where the cost is proportional to the number of changes which took place). The library is here: https://github.com/Polymer/observe-js It may be sufficient for your use case (as well as act as the polyfill you were attempting to create) or it may simply serve as documentation for the processing that is required. Thanks again for your feedback and have fun. Cheers Rafael On Sun, Feb 16, 2014 at 5:25 AM, Woodlock, Don (GE Healthcare) don.woodl...@med.ge.com wrote: HI Rafael et al, I have some feedback into the Object.observe proposal. Now I may be missing something so any clarification or education would be appreciated as well. But I do love this particular spec and can’t wait to see it implemented. But while I was implementing a pseudo-polyfill of it for my own purposes, I noticed an ‘information hole’ in the ChangeRecords design. This is due to the asynchronous nature of the notification delivery and that subsequent mutations may have occurred by the time the notification is ‘delivered’. In particular I believe a new ‘added’ property is needed to the ChangeRecords of the splice transaction of an array mutation in the Array.observe design. Here’s the particular situation: First of all I’m assuming that the purpose of the ChangeRecords is to give the ChangeObserver enough information, beyond the fact that a change occurred, so that it doesn’t have to reprocess everything, but can be specific and efficient based on what in particular has changed. For example if I have a view that lists a bunch of students and it’s observing an array of students, if a student gets added to the array, I’d like to know enough so the view can just add the one student and doesn’t have to redisplay the entire list because it knows the array has changed somehow. Secondly I’ll assuming that the Chrome Canary implementation of Array.observe is suitably similar to the spec as that’s where I have been learning about what this design looks like in practice. Let’s say you have the array: [“c”, “d”, “f”]. If you are observing the array, and this operation occurs myArray.unshift(“b”), you will get the following notification: type = “splice”, removed = [], object: pointer to the array index: 0 addedCount: 1 You would naturally determine what was added via changeRecord.object.slice(changeRecord.index, changeRecord.index + changeRecord.addedCount); That would show you that “b” got added. Subsequently (and with a delay), if you did myArray.unshift(“a”);, you will get an identically looking notification, and through the same approach, you would see that “a” got added. You can see this if you run the first attachment in Chrome Canary. If you run this, you can see in the console log that the fact that the changeObserver determines ‘b’ and then ‘a’ were added
Re: Object.observe feedback
BTW, here's your example using observe-js: http://jsbin.com/leh/1/edit On Sun, Feb 16, 2014 at 7:50 AM, Rafael Weinstein rafa...@google.comwrote: Hi Don, Thanks for the thoughtful feedback. I'm very glad you're excited about the feature. The short answer to your question is: the data you want is provided, but your processing needs to be more sophisticated. [BTW, The Chrome/V8 implementation (to the best of my knowledge) fully implements the latest spec for Object.observe] Basically, you're making an assumption about processing log data which is understandable, but unfortunately false. Though it would be nice, it's simply not possible to process each change record by looking at the final state of the observed object. Object.observe provides full information about the changes that occur, but depending on what view you want, you may need to do some processing to get the right answer. Based on the use-case you describe, it sounds like you have a very common desire -- to synchronize two objects, one of which has changed. The pattern requires what I'll call a diff in time view of the changes. In other words: from time 0 to time 1, what's the minimal set of changes I would need to apply to a copy of the observed object at time 0 in order to transform it into a copy of object at time 1? As you've found, Object.observe doesn't provide you this view of things. It provides you with a log of what happened along the way. However, you can use the log view as input into a transform which will provide you with the diff view. I've provided a JS library which serves multiple purposes: -A handy library for those who want the diff view of things -A reference implementation of some of these algorithms -A polyfill so that you may use this functionality in browsers that don't implement Object.observe (the polyfil mode has less desirable performance -- specifically the cost to determine what has changed is proportional to the total set of observed objects -- as opposed to Object.observe where the cost is proportional to the number of changes which took place). The library is here: https://github.com/Polymer/observe-js It may be sufficient for your use case (as well as act as the polyfill you were attempting to create) or it may simply serve as documentation for the processing that is required. Thanks again for your feedback and have fun. Cheers Rafael On Sun, Feb 16, 2014 at 5:25 AM, Woodlock, Don (GE Healthcare) don.woodl...@med.ge.com wrote: HI Rafael et al, I have some feedback into the Object.observe proposal. Now I may be missing something so any clarification or education would be appreciated as well. But I do love this particular spec and can’t wait to see it implemented. But while I was implementing a pseudo-polyfill of it for my own purposes, I noticed an ‘information hole’ in the ChangeRecords design. This is due to the asynchronous nature of the notification delivery and that subsequent mutations may have occurred by the time the notification is ‘delivered’. In particular I believe a new ‘added’ property is needed to the ChangeRecords of the splice transaction of an array mutation in the Array.observe design. Here’s the particular situation: First of all I’m assuming that the purpose of the ChangeRecords is to give the ChangeObserver enough information, beyond the fact that a change occurred, so that it doesn’t have to reprocess everything, but can be specific and efficient based on what in particular has changed. For example if I have a view that lists a bunch of students and it’s observing an array of students, if a student gets added to the array, I’d like to know enough so the view can just add the one student and doesn’t have to redisplay the entire list because it knows the array has changed somehow. Secondly I’ll assuming that the Chrome Canary implementation of Array.observe is suitably similar to the spec as that’s where I have been learning about what this design looks like in practice. Let’s say you have the array: [“c”, “d”, “f”]. If you are observing the array, and this operation occurs myArray.unshift(“b”), you will get the following notification: type = “splice”, removed = [], object: pointer to the array index: 0 addedCount: 1 You would naturally determine what was added via changeRecord.object.slice(changeRecord.index, changeRecord.index + changeRecord.addedCount); That would show you that “b” got added. Subsequently (and with a delay), if you did myArray.unshift(“a”);, you will get an identically looking notification, and through the same approach, you would see that “a” got added. You can see
Re: Rev21 ES6 Draft now available
Nit: 9.1.10 [[Delete]] (P) Steps 5 6 should be steps 4a 4b (lost an indent) On Fri, Nov 8, 2013 at 12:25 PM, Allen Wirfs-Brock al...@wirfs-brock.comwrote: PDFs and .doc file available at http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts#november_8_2013_draft_rev_21 New in this revision: • Updated Module Syntax and static semantics • Scripts no longer may contain import statements • Specified how to determine if a call is in tail position • The call and apply functions now internally do tail calls to the target function • Tweaked the new operator so it will work in tail position • Eliminated the [[Invoke]] MOP operation • Calling the next method of an completed generator returns a “done” result instead of throwing • The length property of bound functions is now configurable/non-writable • Clarified requirements of String localeCompare when no language sensitive comparison support is available. • Tweaked the ordering of a few steps in Array.from to enable self-hosting using for-of • Added ToInt8 and similar abstract operation • Defined name property of %TypedArray% and the individual typed array constructors • Significant fixed to yield * evaluation semantics • Fixed handling of identifier ‘yield’ in generator function parameter lists • A little static semantic cleanup making sure that FunctionDeclarations and GeneratorDeclarations have the same top level scoping rules ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Changes to Object.observe based on feedback from the September discussion
Note that these proposed changes are now reflected in the Object.observe spec text: http://wiki.ecmascript.org/doku.php?id=harmony:observe On Thu, Oct 17, 2013 at 3:09 PM, Rafael Weinstein rafa...@google.comwrote: At the September meeting, the committee discussed Object.observe. Below is a summary of the feedback, along with proposed changes to the spec. 1) Inconsistent naming of changeRecord types The spec currently defines the following types: 'new', 'updated', 'deleted', 'reconfigured', 'prototype' 'splice', Proposed change: Make changeRecord types all be present tense: 'add', 'update', 'delete', 'reconfigure', 'setPrototype', 'splice' 2) An object becoming non-extensible isn't observable Proposed change: Add a 'preventExtensions' type. 3) Concern about namespace collisions of future change type. Proposed change: None. Adding an explicit namespace to changeRecords is overkill. Future objects will simply need to ensure that added type names are unique. 4) notifier.performChange should allow a returned object from its changeFn to be used as the notification object. E.g. notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; return { amount: amount }; }); as short hand for embiggin: function(int amount) { notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; }); notifier.notify({ type: 'embiggened', amount: amount }); } Proposed change: Support this. If the return value of the changeFn is an object, then emit a notification on the notifier's |target| with the same type as that used for the performChange. 5) If a changeFn provided to performChange throws before completion, an observer who accepts the performed change type won't get precise information about which parts of the modification succeeded. Proposed Change: None. The concern here about fault tolerance here is valid. The problem is that a central motivation of the performChange mechanism is performance, and the solution to this problem negates the main performance benefit -- the ability in common cases to avoid the accounting costs of generating the information for the lower-level changes. IOW, in order to have failure result in the higher-level observer hearing about the succeeded portion of the lower-level mutations, the system will have to incur much of the cost of generating these records in all cases. The bright spot here is that the success criteria that Mark proposed still likely holds in that if a full mirror is maintained via observation, and operations are deterministic, then the failure will occur on both sides in the same way and the two sides will stay in sync. 6) Object.observe(obj, callback, opt_acceptList) implements a JS antipattern: the callback argument isn't in the final position. Proposed change: None. Use of the final argument will be *extremely* rare. It's mostly there so that domain objects can expose custom observe methods which specify the correct accept types, e.g. Array.observe =~ function(object, callback) { return Object.observe(object, callback, ['add', 'update', 'delete', 'splice']) } There are three possible solutions to this concern: (1) make callback the final argument, (2) Object.observe should take an arguments object, and (3) Have Object.observe type check the second argument looking for either a function or an array (support implicit multiple call signatures). I'm interested in other's thoughts on this, but given the likely rarity of providing the final argument, none of these seems like an improvement. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Changes to Object.observe based on feedback from the September discussion
At the September meeting, the committee discussed Object.observe. Below is a summary of the feedback, along with proposed changes to the spec. 1) Inconsistent naming of changeRecord types The spec currently defines the following types: 'new', 'updated', 'deleted', 'reconfigured', 'prototype' 'splice', Proposed change: Make changeRecord types all be present tense: 'add', 'update', 'delete', 'reconfigure', 'setPrototype', 'splice' 2) An object becoming non-extensible isn't observable Proposed change: Add a 'preventExtensions' type. 3) Concern about namespace collisions of future change type. Proposed change: None. Adding an explicit namespace to changeRecords is overkill. Future objects will simply need to ensure that added type names are unique. 4) notifier.performChange should allow a returned object from its changeFn to be used as the notification object. E.g. notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; return { amount: amount }; }); as short hand for embiggin: function(int amount) { notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; }); notifier.notify({ type: 'embiggened', amount: amount }); } Proposed change: Support this. If the return value of the changeFn is an object, then emit a notification on the notifier's |target| with the same type as that used for the performChange. 5) If a changeFn provided to performChange throws before completion, an observer who accepts the performed change type won't get precise information about which parts of the modification succeeded. Proposed Change: None. The concern here about fault tolerance here is valid. The problem is that a central motivation of the performChange mechanism is performance, and the solution to this problem negates the main performance benefit -- the ability in common cases to avoid the accounting costs of generating the information for the lower-level changes. IOW, in order to have failure result in the higher-level observer hearing about the succeeded portion of the lower-level mutations, the system will have to incur much of the cost of generating these records in all cases. The bright spot here is that the success criteria that Mark proposed still likely holds in that if a full mirror is maintained via observation, and operations are deterministic, then the failure will occur on both sides in the same way and the two sides will stay in sync. 6) Object.observe(obj, callback, opt_acceptList) implements a JS antipattern: the callback argument isn't in the final position. Proposed change: None. Use of the final argument will be *extremely* rare. It's mostly there so that domain objects can expose custom observe methods which specify the correct accept types, e.g. Array.observe =~ function(object, callback) { return Object.observe(object, callback, ['add', 'update', 'delete', 'splice']) } There are three possible solutions to this concern: (1) make callback the final argument, (2) Object.observe should take an arguments object, and (3) Have Object.observe type check the second argument looking for either a function or an array (support implicit multiple call signatures). I'm interested in other's thoughts on this, but given the likely rarity of providing the final argument, none of these seems like an improvement. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Changes to Object.observe based on feedback from the September discussion
On Thu, Oct 17, 2013 at 3:09 PM, Rafael Weinstein rafa...@google.comwrote: At the September meeting, the committee discussed Object.observe. Below is a summary of the feedback, along with proposed changes to the spec. 1) Inconsistent naming of changeRecord types The spec currently defines the following types: 'new', 'updated', 'deleted', 'reconfigured', 'prototype' 'splice', Proposed change: Make changeRecord types all be present tense: 'add', 'update', 'delete', 'reconfigure', 'setPrototype', 'splice' 2) An object becoming non-extensible isn't observable Proposed change: Add a 'preventExtensions' type. 3) Concern about namespace collisions of future change type. Proposed change: None. Adding an explicit namespace to changeRecords is overkill. Future objects will simply need to ensure that added type names are unique. 4) notifier.performChange should allow a returned object from its changeFn to be used as the notification object. E.g. notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; return { amount: amount }; }); as short hand for embiggin: function(int amount) { notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; }); notifier.notify({ type: 'embiggened', amount: amount }); } copy/paste error. This should have been: as short hand for: notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; }); notifier.notify({ type: 'embiggened', amount: amount }); Proposed change: Support this. If the return value of the changeFn is an object, then emit a notification on the notifier's |target| with the same type as that used for the performChange. 5) If a changeFn provided to performChange throws before completion, an observer who accepts the performed change type won't get precise information about which parts of the modification succeeded. Proposed Change: None. The concern here about fault tolerance here is valid. The problem is that a central motivation of the performChange mechanism is performance, and the solution to this problem negates the main performance benefit -- the ability in common cases to avoid the accounting costs of generating the information for the lower-level changes. IOW, in order to have failure result in the higher-level observer hearing about the succeeded portion of the lower-level mutations, the system will have to incur much of the cost of generating these records in all cases. The bright spot here is that the success criteria that Mark proposed still likely holds in that if a full mirror is maintained via observation, and operations are deterministic, then the failure will occur on both sides in the same way and the two sides will stay in sync. 6) Object.observe(obj, callback, opt_acceptList) implements a JS antipattern: the callback argument isn't in the final position. Proposed change: None. Use of the final argument will be *extremely* rare. It's mostly there so that domain objects can expose custom observe methods which specify the correct accept types, e.g. Array.observe =~ function(object, callback) { return Object.observe(object, callback, ['add', 'update', 'delete', 'splice']) } There are three possible solutions to this concern: (1) make callback the final argument, (2) Object.observe should take an arguments object, and (3) Have Object.observe type check the second argument looking for either a function or an array (support implicit multiple call signatures). I'm interested in other's thoughts on this, but given the likely rarity of providing the final argument, none of these seems like an improvement. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Changes to Object.observe based on feedback from the September discussion
On Thu, Oct 17, 2013 at 3:09 PM, Rafael Weinstein rafa...@google.comwrote: At the September meeting, the committee discussed Object.observe. Below is a summary of the feedback, along with proposed changes to the spec. 1) Inconsistent naming of changeRecord types The spec currently defines the following types: 'new', 'updated', 'deleted', 'reconfigured', 'prototype' 'splice', Proposed change: Make changeRecord types all be present tense: 'add', 'update', 'delete', 'reconfigure', 'setPrototype', 'splice' 2) An object becoming non-extensible isn't observable Proposed change: Add a 'preventExtensions' type. 3) Concern about namespace collisions of future change type. Proposed change: None. Adding an explicit namespace to changeRecords is overkill. Future objects will simply need to ensure that added type names are unique. 4) notifier.performChange should allow a returned object from its changeFn to be used as the notification object. E.g. notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; return { amount: amount }; }); as short hand for embiggin: function(int amount) { notifier.performChange('embiggened', () = { this.width *= amount; this.height *= amount; }); notifier.notify({ type: 'embiggened', amount: amount }); } Proposed change: Support this. If the return value of the changeFn is an object, then emit a notification on the notifier's |target| with the same type as that used for the performChange. 5) If a changeFn provided to performChange throws before completion, an observer who accepts the performed change type won't get precise information about which parts of the modification succeeded. Proposed Change: None. The concern here about fault tolerance here is valid. The problem is that a central motivation of the performChange mechanism is performance, and the solution to this problem negates the main performance benefit -- the ability in common cases to avoid the accounting costs of generating the information for the lower-level changes. IOW, in order to have failure result in the higher-level observer hearing about the succeeded portion of the lower-level mutations, the system will have to incur much of the cost of generating these records in all cases. The bright spot here is that the success criteria that Mark proposed still likely holds in that if a full mirror is maintained via observation, and operations are deterministic, then the failure will occur on both sides in the same way and the two sides will stay in sync. Put another way: If your use case includes observing changes which may partially succeed as a recoverable error-case, you should observe at a level of granularity which ensures you hear about which parts succeeded. 6) Object.observe(obj, callback, opt_acceptList) implements a JS antipattern: the callback argument isn't in the final position. Proposed change: None. Use of the final argument will be *extremely* rare. It's mostly there so that domain objects can expose custom observe methods which specify the correct accept types, e.g. Array.observe =~ function(object, callback) { return Object.observe(object, callback, ['add', 'update', 'delete', 'splice']) } There are three possible solutions to this concern: (1) make callback the final argument, (2) Object.observe should take an arguments object, and (3) Have Object.observe type check the second argument looking for either a function or an array (support implicit multiple call signatures). I'm interested in other's thoughts on this, but given the likely rarity of providing the final argument, none of these seems like an improvement. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: microtask timeouts (was Re: setImmediate)
FWIW, I very much agree with Dave on this point. My conceptual model for microtask work is just a re-ordering of work which otherwise would have run synchronously, but wanted to be run with a fresh stack. Microtask non-termination should not be different from regular script non-termination. On Mon, Aug 12, 2013 at 6:09 PM, David Herman dher...@mozilla.com wrote: On Aug 12, 2013, at 5:43 PM, David Bruant bruan...@gmail.com wrote: - I see *no* reasonable alternative to runaway microtask churn other than slow-script dialog. So did Dominic [1]. I suggested something else [2] and he found the idea interesting. What do you think? Quoting you from [2] https://mail.mozilla.org/pipermail/es-discuss/2013-August/032630.html you said: Maybe implementations could decide to break a microtask chain, but instead of prompting a dialog, they just break it and call a callback (later, in a different task, not microtask) so that the script knows and can try to recover. It is an interesting idea, I missed it the first time around; you might describe it as an asynchronous TimeoutException. I'm thinking about it, but I'm pretty skeptical. It's still effectively preemption semantics. At any nondeterministic (and not portably defined) point, your code can simply be stopped. It's not even clear what the atomicity guarantees would be around valid preemption points in the semantics. For example, can you preempt code halfway through the modification of a 64-bit word? Can you preempt code that hasn't spilled its registers back to memory? Am I scaring you yet? ;-) Even if we could provide a fully well-specified definition for concurrent interruption, I really have no idea how code could ever realistically recover from such an event. The only thing the system tells you is at some point in some turn we just stopped you from whatever you were doing, and now you're expected to reconstruct your state. This reminds me of exception safety in C++. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Synchronous Object.observe but Asynchronous Object.unobserve ?
If you wish, you can maintain a WeakMap of observed objects. If you wish to never process a changeRecord for an object you've stopped observing, you can simply check the WeakMap to see if it's still observed. On Fri, Nov 2, 2012 at 9:50 PM, Andrea Giammarchi andrea.giammar...@gmail.com wrote: fair enough, but I want to know what I am seeing is recorded and the TV is switched off ... how? Flagging records? Flagging objects? Via getNotifier ? On Fri, Nov 2, 2012 at 11:56 AM, Erik Arvidsson erik.arvids...@gmail.com wrote: On Fri, Nov 2, 2012 at 12:22 PM, Andrea Giammarchi andrea.giammar...@gmail.com wrote: How to make this simple ... if I switch off the TV I don't expect any eco after ... I don't care about the program, it should not bother me. If you stick to the TV analogy... You don't want Tivo to erase what it just recorded just because you stopped recording. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Synchronous Object.observe but Asynchronous Object.unobserve ?
Andrea, I believe the example is correct. The way the API works is this: Object.observe and Object.unobserve both *synchronously* register/unregister your callback as observing/unobserving any given object. The asynchrony has to do with having changeRecords delivered -- that happens asynchronously. I don't understand the leak you are describing. Perhaps you can give a concrete example and how it goes wrong. On Thu, Nov 1, 2012 at 9:32 PM, Andrea Giammarchi andrea.giammar...@gmail.com wrote: Just wondering if this is actually meant/expected, I am talking about the example here: http://wiki.ecmascript.org/doku.php?id=harmony:observe#example and the fact it should show something in console while in my opinion that should show nothing since the Object.unobserve is called in the same tick Then I read the algo and I wonder if this won't create many problems, i.e. enabling a new way to leak objects through observers that should not be called once the object is not observed anymore, specially because there's no way to understand if the object is observed or not, isn't it? Thanks for any sort of clarification. br ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Synchronous Object.observe but Asynchronous Object.unobserve ?
Take for example: function myCallback(recs) { console.log(recs.length); } var obj = {}; Object.observe(obj, myCallback); obj.a = 1; // enqueues changeRecord obj.b = 2; // enqueues changeRecord Object.unobserve(obj, myCallback); obj.c = 3; // does not enqueue changeRecord In the above example, myCallbacks will be invoked with two changeRecords and output 2 It sounds like you are worried about callbacks being delivered with changeRecords pointing to objects that they have stopped observing. This can and will happen. It's just something that users of the API need to understand. It doesn't strike me as a problem, but perhaps I'm missing something...? On Fri, Nov 2, 2012 at 5:04 PM, Andrea Giammarchi andrea.giammar...@gmail.com wrote: hey, thanks for coming back. The asynchronous unobserve in the meaning that Object.unobserve is performed synchronously but the delivery of records is asynchronous and performed regardless the object is not observed anymore. Inside the observer each record can point to an object that is no more observed and I am not sure if there is a way to understand this or if the observer should perform the getNotifier(obj) check. The way I would implement this is that when the Object.unobserve(obj) is called, the queue, if any, with all previous records, is delivered at that time, and not during the next tick. Thoughts? On Fri, Nov 2, 2012 at 5:17 AM, Rafael Weinstein rafa...@chromium.org wrote: Andrea, I believe the example is correct. The way the API works is this: Object.observe and Object.unobserve both *synchronously* register/unregister your callback as observing/unobserving any given object. The asynchrony has to do with having changeRecords delivered -- that happens asynchronously. I don't understand the leak you are describing. Perhaps you can give a concrete example and how it goes wrong. On Thu, Nov 1, 2012 at 9:32 PM, Andrea Giammarchi andrea.giammar...@gmail.com wrote: Just wondering if this is actually meant/expected, I am talking about the example here: http://wiki.ecmascript.org/doku.php?id=harmony:observe#example and the fact it should show something in console while in my opinion that should show nothing since the Object.unobserve is called in the same tick Then I read the algo and I wonder if this won't create many problems, i.e. enabling a new way to leak objects through observers that should not be called once the object is not observed anymore, specially because there's no way to understand if the object is observed or not, isn't it? Thanks for any sort of clarification. br ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Object.observe and observing computed properties
[Sorry, this time from the right email] Object.deliverChangeRecords allows A to be a strategy in the possible future that Steve describes (if reads were to generate changeRecords) [Just to be clear: I *don't* think it makes sense to include reads in the set of changeRecords generated by Object.observe() at this point] The basic idea is that every computed property has around advice that clears its pending delivery queue before and after invocation of the actual function so it can disambiguate reads generated during the invocation from outer (previous or later) or inner (sub-invocations of computed properties) reads. On Wed, Sep 19, 2012 at 2:09 PM, Brendan Eich bren...@mozilla.com wrote: From A, B and C as alternatives, especially A and C, it seems you want synchronous read intercession, but are happy with Object.observe's asynchronous write intercession? If so, then the plan interference objection is fatal. If not, then how would async read intercession work? Callbacks and promises are not going to fly. /be Steve Sanderson wrote: Following this discussion, Rafael and I talked about various strategies that an MV* library could use to detect dependencies from arbitrary expressions and code blocks, as would be needed to achieve the kinds of niceties present in Knockout.js/Batman.js etc. Some of these tie in with Object.observe more than others. The upshot is that we don't have a single most compelling way to do this kind of dependency detection with Object.observe, but it would be possible to augment Object.observe to add that ability in a future language version (see technique A below), or alternatively, libraries could use somewhat less clean techniques to achieve it with proxies/accessors alone, regardless of Object.observe (see techniques B and C below). So as a library developer I would in principle be happy to see Object.observe added to ES, since it appears to be a step in the right direction. But I would caution that unless read notifications were added (see technique A), my library (knockout.js) couldn't use it to achieve something as clean as its existing semantics, so we'd most likely be waiting for future improvements before being able to use Object.observe. Regards Steve *_Appendix: the techniques we considered_* * *Technique A: Add read notifications to Object.observe (either now, or in a future ECMAScript version)* o Just as the existing Object.observe proposal delivers notification of property writes for specific objects, a symmetrical API could deliver notification of property reads for specific objects o Pros: it requires no proxies or accessors, so works with raw data o Cons: requires language support, like Object.observe does for write notifications * *Technique B: Membrane-style proxies transitively capture all chains of properties read from a given object* o The logic that parses/evaluates binding expressions could supply a specially wrapped version of the underlying data that uses a proxy to log property reads o Pros: doesn't require language support; ties in with Object.observe in that once you know what properties were read, you can use Object.observe to subscribe to write notifications o Cons: because the proxies aren't the real underlying data objects, it's possible to get into confusing scenarios where things don't work, for example if you read a property of a closure-captured variable, that won't be logged and hence the framework can't auto-update when that property changes * *Technique C: Monkeypatch all model data properties with accessors that log reads* o Some utility function would walk the object graph and replace all properties with special accessors o Pros: doesn't require language support; also doesn't even require Object.observe since you might as well also replace setters with ones that trigger notification on change o Cons: very intrusive - permanently modifies the developer's data structures On Fri, Aug 31, 2012 at 10:38 AM, François REMY fremycompany_...@yahoo.fr mailto:fremycompany_...@yahoo.fr wrote: *From:* Alex Russell mailto:slightly...@google.com *Sent:* Thursday, August 30, 2012 7:44 PM *To:* ste...@stevensanderson.com mailto:ste...@stevensanderson.com *Cc:* es-discuss@mozilla.org mailto:es-discuss@mozilla.org *Subject:* Re: Object.observe and observing computed properties On Wed, Aug 29, 2012 at 11:09 AM, Steve Sanderson fla...@gmail.com mailto:fla...@gmail.com wrote: Knockout developers are used to this sort of thing updating automatically whenever you modify the price of any item, or when you add or remove items to the array. It would be very inconvenient to have to somehow declare dependencies
Re: Experimental implementation of Object.observe JS Utilitylibrary now available
Hi François, Thanks so much for your thoughtful consideration of the Object.observe() proposal. Here's my take on your counter-proposal: Interestingly, what you've focused on is the one thing we intentionally left out of the Object.observe() proposal, namely: observing computed properties. In that way, I don't see what you've proposed as an alternative, but rather supplementary. First, I'd like to point out that, while most people these days seem to say databinding and specifically mean updating a UI, there are important use cases which depend on observing mutations to objects which are entirely distinct. Note that what you've proposed, doesn't include the following abilities: 1) Discovering when new properties are added to objects -- which is particularly important in the case of Arrays, where you often want to bind to the *set* of elements in an Array 2) Knowing the order of changes which occurred -- this is important to many use cases, including persisting changes to domain objects and efficiently computing effective changes to complex data structures (a DOM tree implemented in JS would be one example). 3) Discovering when properties have been reconfigured -- which is important if your strategy for observing computed properties is comparatively expensive, and you need to know *when* to employ it. 4) Generally, having full knowledge of what happened to an object so as to able to efficiently mirror it -- which is important in some synchronization strategies. Ok, with that out of the way, I think the topic you've raised: computed properties, deserves its own thread -- so I'll start a new thread for that purpose and put my thoughts there. On Sun, Aug 26, 2012 at 6:14 AM, François REMY fremycompany_...@yahoo.fr wrote: Here’s my take on the binding thing: http://fremycompany.com/BG/2012/ECMAScript-Binding-Manager-951/ Key features: - Do not require to have a reference on an object to bind to it (binding is implicit and managed by the browser). - Accessors, function calls and inner dependencies are managed automatically. - Since the browser manage most the binding wiring, it can makes tons of optimizations. - It’s trivial to use for developers. Have a look ;-) From: Alex Russell Sent: Thursday, August 23, 2012 11:47 AM To: Brandon Benvie Cc: ste...@stevensanderson.com ; es-discuss@mozilla.org Subject: Re: Re: Experimental implementation of Object.observe JS Utilitylibrary now available On Thu, Aug 23, 2012 at 7:06 AM, Brandon Benvie bran...@brandonbenvie.com wrote: I would say it is most definitely not the concern of Observe to watch reads and between accessors and Proxies we have all the tools we need for that. I think that misreads the situation. Having proxies available might work for this, but is it the right (implied) *UI* for it? I.e., if you need to do half of your work with observe() and then pivot over to proxies for the other half...that strikes me as strange. There might be good reasons not to, but saying you can do it with what we've got is always tautological in a turing machine = ) With the ability to keep present on notifications of changes via observe it's actually possible to implement a mirror that can be emit change events (by explicitly mirroring changes on the original target changes) and provide the benefits of the observe api to listeners, and then implement any kind of additional tracking on top of that either by using accessors or being a proxy. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Object.observe and observing computed properties
Steve Sanderson (author of the excellent KnockoutJS framework) and François REMY both raised the issue of observing computed properties WRT to the Object.observe() proposal. Having thought about this problem while helping to author Object.observe, my thoughts are as follows: First, I think you need to look at the problem the right way. Observing computed properties is kind of non-sensical. What this translates to is observe when the *return value* of an anonymous function invocation *will be* different from the last invocation. I think the only reasonable way to look at it is this: imagine that a *data property* can be defined whose value can only be set by assigning it the return value of a given function. Observing when a data property changes value is trivial. The problem becomes: deciding when the function should be re-evaluated. Looked at like this, the first thing that becomes obvious is that there are a class of functions which should never be used: those functions that can spontaneously change value. e.g. var i = 1; function getVal { return ++i; } function getVal2 { return Math.random(); } function getVal3 { return myElement.offsetHeight; } [I actually think at this point it becomes clear that, because the task at hand isn't solvable in general, it's not appropriate to include support for it at the language level, but lets continue]. That said, those functions: -whose output is dependent only on the value of a discrete set of inputs, (i.e. are stateless) -don't modify their inputs -will always return the same output value for the same set of inputs can be sensibly used for computed property functions. It's worth noting that even this can be easy to get wrong. For example, many webdevs might not realize that var firstName = 'Rafael'; var lastName = 'Weinstein'; function getVal() { return [firstName, lastName]; } doesn't meet this criteria as its return value is always a different Array object. Assuming that you've been careful to pick an appropriate function, there are two approaches to knowing when to reevaluate it: 1) Dirty-checking: Immediately before each time you need the value of the dependent property. 2) Dependency observation: When one or more of its inputs have changed value. At this point, you have only trade-offs. (1) Is potentially expensive and hard to do at exactly the right time, but (2) requires having proper knowledge of the function's inputs. Obtaining the set of inputs for (2) can be done in two ways: 2a) Require the function author to declare them. 2b) Attempt to discover them by running the function and observing which inputs it accesses. (2a) requires some careful attention on the part of the function author, so in some sense, if (2b) were possible, it would be ideal. This brings us to what KnockoutJS does and what François proposed, so let's consider it. The first problem is what I discussed above, that creating an *appropriate* function is potentially tricky and/or hard to understand, and there isn't any way to statically determine if a function is or is not appropriate. The second problem is that doing this risks discovering inputs that aren't really inputs at all. In other words, the function, just be being invoked happens to touch a wide swath of objects, even though they aren't dependencies of the function. This is bad because it would cause the system to observe these objects, which, given modern VMs, will cause them to de-optimize and become slower to access Thus, offering language-level support for (2b) puts developers in the risky situations of authoring computed property functions which may A) not fire their notifications, even though they appear to have changed value B) become a go-slow button for their entire application ...with no good recourse to discover why either is happening. Note that François's proposal included a mitigation of (B), in that you need to whitelist objects as potential discoverable dependencies. This helps some with the risk of discovering too many dependencies, but it also risks not discovering enough dependencies, which becomes problem (A) again. Thus, what we have is a problem which is really solved through convention, not through an abstract solution, and thus the most sensible thing to do is leave it to authors to make trade-offs for themselves about the pros cons of the various approaches and the conventions they imply. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Re: Experimental implementation of Object.observe JS Utility library now available
Hi Steve, Thanks for joining the conversation. =-) The automatic dependency discovery that Knockout does is rather cool. My sense has been that Proxy is a better tool for this job than is expanding the semantics of Object.observe() to include reads. Object.observe() only operates on objects which are specifically observed, so something like get val function() { this.foo.bar + this.bat.baz; } Would only report access to this.foo and this.bat, but not foo.bar and bat.baz. While applying the function to a proxy wrapper allows for the creation of a membrane through which you can discover dependencies not available on the local object. Is my thinking flawed? Note that the Object.observe() specifically reports when properties are reconfigured such that any approach you take to computed properties can know when it needs to invoke its strategy and when it can rely on the system-generated change records. On Wed, Aug 22, 2012 at 3:34 AM, Steve Sanderson fla...@gmail.com wrote: This is fantastic - thanks for pushing this forwards, Rafael! For context, I'm part of the knockout.js (a JavaScript MV* library) team, so I have some interest in how this could work out. This spec has a lot of potential to make MVC-style coding far simpler and more robust, both for framework developers and web app developers. Although the semantics of the Object.observe proposal are different in a few ways from what Knockout and similar frameworks use for observability, it certainly looks applicable enough to the same design patterns and APIs. There's one significant extra aspect of observability that Knockout, Batman, CanJS, and other MVC-type frameworks rely on that isn't covered as far as I can tell by the proposal so far. These frameworks can automatically determine the dependencies of an arbitrary block of code. For example, if there is a block of code that determines the output of a computed property, like this: function fullName() { return firstName + + lastName }; ... then if you use such a function during a declarative binding, those frameworks' observability mechanisms will automatically know which underlying observable properties it depends on. This is possible because the frameworks' observabilty mechanisms can notify on read as well as on write. This ends up being a very powerful and flexible feature whereby the framework can manage arbitrary and dynamically-changing dependency chains, and the developer can robustly call arbitrary custom functions in computed property evaluators and bindings. These facilities could be made possible in the Object.observe proposal by adding one further primitive feature. Just as you can register for notifications on *write*, you'd ideally also be able to register for separate notifications on *read*. Typically only framework code would do that - application code wouldn't usually need to. The actual dependency detection logic would differ depending on whether read notifications were delivered synchronously or asynchronously, but then everything else can be built on top of that primitive. Please let me know if you want more detailed descriptions of how any of this works in Knockout/etc. I'd be happy to suggest how a comparable API might look in the Object.observe world! Regards Steve ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Experimental implementation of Object.observe JS Utility library now available
On Sun, Aug 19, 2012 at 11:25 AM, John J Barton johnjbar...@johnjbarton.com wrote: On Fri, Aug 17, 2012 at 9:49 PM, Rafael Weinstein rafa...@chromium.org wrote: A synchronous observation mechanism provides an attacker too many opportunities for a plan interference attack. If you'll recall, an earlier synchronous proposal died for this reason. That is an excellent reason. I have two others: 1) It's a terrible design pattern to encourage. Webdevs will absolutely use it and learn the hard way, just like we did with Mutation Events that it works fine when we start, but down the road lies nothing but pain and suffering. 2) Synchronous doesn't actually exist -- it's a false option. To explain: When people talk about synchronous what they expect is that they will be notified concurrent with the event happening (this *is happening*). The expectation is that when they are invoked they are observing the world as the event is describing. This is the appeal of synchronous delivery. Here's the rub: unless you plan to only allow a single observer per object, then you have to pick someone to go first. And unless you plan to prevent that person from further mutating the object, the next guy to be called may not observe the world in the state suggested by the synchronous call. In fact, an arbitrary number of mutations can always have occurred by the time any given observer is called, so it's just dishonest API which pretends that a single thing has happened. The correct thing is to inform each observer what *set* of things has happened. So the only questions are: 1) Do you mislead the consumer with API which suggests that only one thing will has happened 2) If not, when do you deliver the set of things: immediately after the mutation occurs, at the end of the turn or ask the UA to schedule a future task. Referring back to my reason (1) This question was debated extensively with DOM Mutation Observers and unanimously decided that the end of the turn was the only good solution. immediately puts all code in danger of having its runtime assumptions invalidated after every operation which mutates objects and future task is far too late to be useful for most almost all use cases. I can understand how batched changes and end-of-turn asynchronous calls are a good match. The development model is now here are the changes from this turn rather than here is a change. But I don't understand how end-of-turn asynchronous calls helps with the multiple independent listeners problem. If a listener can mutate the DOM, then change-listeners depend upon change-listeners. The relative timing of the listener calls and the non-listener DOM mutations does not change that dependency. And once change-listeners mutate the DOM then the API of here are the changes from this turn again misleads the developer relying on it. Actually, this isn't quite right. It's here are all the changes since the last time you were invoked. I.e. every observer is always delivered all changes to all entities it is observing up to the time that it is invoked. To be concrete, the following invariants always hold: A) When an observer is invoked, is it delivered a sequence of change records representing all changes to entities it is observing -- up to the time of its invocation. B) When an observer is invoked, it is free to mutate entities and do work without risk of being preempted by other observers being notified of changes it makes. C) Conversely, when an observer is invoked, no other script is below it on the stack. D) An observer will be delivered all changes to entities it is observing before the turn ends. These are true for both Object.observe() and for DOM Mutation Observers. In other words, any given observer can be blissfully ignorant of all other actors in the system. It is always delivered a full picture of what has happened in its world, it can act completely independently of other actors, and it will always get all of its changes before the turn ends. Does this address your concern? (I think simplifying the internal browser logic for DOM mutation is all the justification needed for new API for DOM mutation observers). jjb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Experimental implementation of Object.observe JS Utility library now available
On Sat, Aug 18, 2012 at 3:06 PM, Brendan Eich bren...@mozilla.org wrote: Rafael Weinstein wrote: On Fri, Aug 17, 2012 at 8:03 PM, Brendan Eichbren...@mozilla.org wrote: Mark S. Miller wrote: On Fri, Aug 17, 2012 at 6:49 PM, Brendan Eichbren...@mozilla.org mailto:bren...@mozilla.org wrote: All praise to Raf et al., my concern is that something synchronous, plus event loop concurrency and setImmediate, would suffice to bootstrap the rather more elaborate proposal on top of the simpler O.p.watch like fundament. This is not to say we shouldn't standardize higher-level APIs, and instead push that off on library authors to write, and users to download. There's a delicate balance here. We often screw up higher-level abstractions in annoying ways, but perhaps that risk is worth taking. What I'm really getting at is this: why not expose the synchronous primitive and e.l.c. building blocks as well? A synchronous observation mechanism provides an attacker too many opportunities for a plan interference attack. If you'll recall, an earlier synchronous proposal died for this reason. That is an excellent reason. It is, and I should have recited it to the Y U no kids but I hadn't found it expressed concisely. I should have looked harder -- it was recorded in the May 2011 meeting notes: https://mail.mozilla.org/pipermail/es-discuss/2011-May/014748.html Allen: This allows people to break into abstractions by putting observers on objects they don't own. DaveH: Proxies are deliberately less powerful than this in that they don't allow you to attach behaviors to arbitrary objects that you don't own. MarkM: Notification happening synchronously is a security problem. Observers can run at times when code doesn't expect malicious changes. I have two others: 1) It's a terrible design pattern to encourage. Webdevs will absolutely use it and learn the hard way, just like we did with Mutation Events that it works fine when we start, but down the road lies nothing but pain and suffering. This is not a complete reason -- see mutation events -- but I know that history too. What I remember mostly dissuading developers was bad performance -- use a mutation event listener and your DOM got slow -- but any more detailed history would be helpful, here if not in the spec (more below). Apologies. My comment wasn't especially helpful or informative. You are absolutely right that the main reason that webdevs avoided them was because they were horrifically slow. The pain and suffering I was (inelegantly) referring to was that of UA implementors. The pain most acutely felt was that of having to write code which needed to tolerate script tearing the DOM to shreds in the middle of a multiple-step operation. Basically, if Mutation Events had been fast enough and fully deployed (and thus actually used), webdevs would have ended up feeling that pain that UA implementors were trying to ride themselves of (essentially, writing code that couldn't be counted on to run in isolation) 2) Synchronous doesn't actually exist -- it's a false option. To explain: When people talk about synchronous what they expect is that they will be notified concurrent with the event happening (this *is happening*). The expectation is that when they are invoked they are observing the world as the event is describing. This is the appeal of synchronous delivery. Here's the rub: unless you plan to only allow a single observer per object, then you have to pick someone to go first. And unless you plan to prevent that person from further mutating the object, the next guy to be called may not observe the world in the state suggested by the synchronous call. Synchronous != synchronized. In fact, an arbitrary number of mutations can always have occurred by the time any given observer is called, so it's just dishonest API which pretends that a single thing has happened. The correct thing is to inform each observer what *set* of things has happened. Right, the is happening = has happened implies the set. So the only questions are: 1) Do you mislead the consumer with API which suggests that only one thing will has happened 2) If not, when do you deliver the set of things: immediately after the mutation occurs, at the end of the turn or ask the UA to schedule a future task. Referring back to my reason (1) This question was debated extensively with DOM Mutation Observers and unanimously decided that the end of the turn was the only good solution. immediately puts all code in danger of having its runtime assumptions invalidated after every operation which mutates objects and future task is far too late to be useful for most almost all use cases. Thanks, this is good and perhaps we don't need to dig up and summarize the mutation observer debate. But I think the spec (proposal and ECMA-262) should record an informative note
Re: Experimental implementation of Object.observe JS Utility library now available
Hi gaz, Thanks so much for your time. Much care has been taking with this proposal to ensure that it is neutral with respect to the existing JS Object/Security model. As I understand it, the core vulnerability with JSON hacking is the ability to define getters on the Object prototype. Object.observe() does not affect that ability. In order to be notified of changes to an object, you need a reference to it first. E.g. Object.observe(Object.prototype, function doBadThings() { .. }); But if you were able to do this, you could have just as easily gone ahead and done bad things directly to the Object.prototype. Object.observe() doesn't increase your access. If there is something I'm missing, perhaps you can provide a code example of how the attack would work. On Fri, Aug 17, 2012 at 2:50 AM, gaz Heyes gazhe...@gmail.com wrote: Hi Rafael Would this proposal work on the Object prototype? If so then it could be used for JSON hijacking. I'd recommend it didn't. Cheers Gareth ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Experimental implementation of Object.observe JS Utility library now available
On Fri, Aug 17, 2012 at 8:03 PM, Brendan Eich bren...@mozilla.org wrote: Mark S. Miller wrote: On Fri, Aug 17, 2012 at 6:49 PM, Brendan Eich bren...@mozilla.org mailto:bren...@mozilla.org wrote: All praise to Raf et al., my concern is that something synchronous, plus event loop concurrency and setImmediate, would suffice to bootstrap the rather more elaborate proposal on top of the simpler O.p.watch like fundament. This is not to say we shouldn't standardize higher-level APIs, and instead push that off on library authors to write, and users to download. There's a delicate balance here. We often screw up higher-level abstractions in annoying ways, but perhaps that risk is worth taking. What I'm really getting at is this: why not expose the synchronous primitive and e.l.c. building blocks as well? A synchronous observation mechanism provides an attacker too many opportunities for a plan interference attack. If you'll recall, an earlier synchronous proposal died for this reason. That is an excellent reason. I have two others: 1) It's a terrible design pattern to encourage. Webdevs will absolutely use it and learn the hard way, just like we did with Mutation Events that it works fine when we start, but down the road lies nothing but pain and suffering. 2) Synchronous doesn't actually exist -- it's a false option. To explain: When people talk about synchronous what they expect is that they will be notified concurrent with the event happening (this *is happening*). The expectation is that when they are invoked they are observing the world as the event is describing. This is the appeal of synchronous delivery. Here's the rub: unless you plan to only allow a single observer per object, then you have to pick someone to go first. And unless you plan to prevent that person from further mutating the object, the next guy to be called may not observe the world in the state suggested by the synchronous call. In fact, an arbitrary number of mutations can always have occurred by the time any given observer is called, so it's just dishonest API which pretends that a single thing has happened. The correct thing is to inform each observer what *set* of things has happened. So the only questions are: 1) Do you mislead the consumer with API which suggests that only one thing will has happened 2) If not, when do you deliver the set of things: immediately after the mutation occurs, at the end of the turn or ask the UA to schedule a future task. Referring back to my reason (1) This question was debated extensively with DOM Mutation Observers and unanimously decided that the end of the turn was the only good solution. immediately puts all code in danger of having its runtime assumptions invalidated after every operation which mutates objects and future task is far too late to be useful for most almost all use cases. Thanks, I recall -- but this needs to be stated clearly in the spec. I hear from people all the time asking Y U no Object.prototype.watch. Which spec? Is there something you're wanting to see in the text of the Object.observe proposal? /be Object.observe has been carefully designed to strike a good balance between providing non-malicious code useful new powers without providing attackers significant new attack opportunities. The core principle is that a client of an object can anyway observe changes to observable state asynchronously by polling between turns. And a client of an object, if it receives control during a turn, can poll while it has control. To a first approximation, Object.observe can be understood as an optimization of polling. It is actually more powerful than that, but in ways that are beneficial without IMO creating significant new hazards. /be Brandon Benvie wrote: I agree on the above with regard to Proxies. They are awesome and allow for incredible things, but Object.observe fills a different use case that I think is more common at at the user standpoint or at least library standpoint. When you look around at the major JS libraries that exist the problem they are trying to solve (after DOM normalization) is data-binding. Proxy can be used to solve this for new objects or wrapped objects, but that's overkill and may have performance consequences, and has no support for working with existing objects. Proxy and observe end up filling two completely different use-cases, and I would venture to say that observe is the one that most people could make better use of if they had it in their hands today. ___ es-discuss mailing list es-discuss@mozilla.org mailto:es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing
Re: Experimental implementation of Object.observe JS Utility library now available
I've created a bunch of cool demos and a video which attempts to explain the use cases need for Object.observe(). https://plus.google.com/u/1/111386188573471152118 On Mon, Aug 13, 2012 at 12:28 PM, Rafael Weinstein rafa...@chromium.org wrote: Hi all, As promised, here is an experimental implementation of the Object.observe strawman in a branch of v8: https://github.com/rafaelw/v8 [Note that there are Mac Windows binaries of Chromium for everyone's convenience. The links to the binaries are contained in the README.md -- and also at the bottom of the page]. Also, here is a JS Utility library which uses the Object.observe() mechanism and exposes some higher-level and more convenient abstractions (such as path observation array splice computations): https://github.com/rafaelw/ChangeSummary. [Note that this library is to Object.observe as MutationSummary (http://code.google.com/p/mutation-summary/) is to DOM Mutation Observers] Expect (and report) bugs in both and crashes in the v8 impl, but it should be stable enough now for actual experimentation prototyping. Unless someone feels otherwise, we just assume any feedback go directly es-discuss (to this thread is fine) so as not to split away from here any substantive discussion about the feature. Our next step is to align our tests and the ChangeSummary library with Tom's excellent proxy implementation so we'll have two experimental versions which pass the same set of tests (and we can continue to use Tom's proxy impl as a reference spec-in-code]. Enjoy ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Experimental implementation of Object.observe JS Utility library now available
Hi all, As promised, here is an experimental implementation of the Object.observe strawman in a branch of v8: https://github.com/rafaelw/v8 [Note that there are Mac Windows binaries of Chromium for everyone's convenience. The links to the binaries are contained in the README.md -- and also at the bottom of the page]. Also, here is a JS Utility library which uses the Object.observe() mechanism and exposes some higher-level and more convenient abstractions (such as path observation array splice computations): https://github.com/rafaelw/ChangeSummary. [Note that this library is to Object.observe as MutationSummary (http://code.google.com/p/mutation-summary/) is to DOM Mutation Observers] Expect (and report) bugs in both and crashes in the v8 impl, but it should be stable enough now for actual experimentation prototyping. Unless someone feels otherwise, we just assume any feedback go directly es-discuss (to this thread is fine) so as not to split away from here any substantive discussion about the feature. Our next step is to align our tests and the ChangeSummary library with Tom's excellent proxy implementation so we'll have two experimental versions which pass the same set of tests (and we can continue to use Tom's proxy impl as a reference spec-in-code]. Enjoy ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: July 25, 2012 - TC39 Meeting Notes
On Mon, Jul 30, 2012 at 2:56 PM, Aymeric Vitte vitteayme...@gmail.com wrote: Le 28/07/2012 01:55, Rick Waldron a écrit : Explanation of specification history and roots in newer DOM mutation mechanism. AWB: Is this sufficient for implementing DOM mutation event mechanisms? RWS: Yes, those could be built on top of Object.observe Probably I must be misreading the proposal (again), but if you take a js DOM project where almost all attributes are handled via getters/setters, how can we observe something ? The point wouldn't be to observe DOM changes directly via Object.observe() by user script. The DOM Mutation API is different in several ways from Object.observe() (different API surface area, different vocabulary of changes, etc...) One approach would be have the DOM storage internally be graphs of simple data. The implementation can observe changes and then compute a transform of the data changes it receives into the necessary DOM mutations, which it then broadcasts. I don't have an opinion of whether it would be a good idea to take this approach (my guess is that standard trade-offs of complexity memory vs speed would apply). Allen's question was whether it would be possible. -- jCore Email : avi...@jcore.fr Web :www.jcore.fr Webble : www.webble.it Extract Widget Mobile : www.extractwidget.com BlimpMe! : www.blimpme.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Updates to Object.observe
On Wed, Jul 18, 2012 at 3:20 PM, Erik Arvidsson erik.arvids...@gmail.com wrote: On Tue, Jul 17, 2012 at 8:25 PM, Russell Leggett russell.legg...@gmail.com wrote: One of the absolutely most useful things I would not want to live without in a databinding framework is bind to properties or property paths. It is extremely common to want a handler to only listen for changes to a single property - the same way event handlers do. Something like: Object.observe(o,x,observer); Which would only be notified of changes to x, instead of having to check which property each time. Its a minor thing, but common. In my framework it is also possible to databind to a whole path - so lets say something like: Object.observe(o,x.y, observer); This would be attached at o, but it listens down the whole path, so a change to the y on x would fire, but a change to x would fire also fire with the new x's y property. This would automatically remove any observers from the old x.y path and attach observers to the next x.y path. This sort of thing is incredibly common and powerful in data bound templates. I agree that this is a very common feature. For this iteration, we wanted to provide the minimal building blocks to allow these kind of things to be built. A way of firing the callback immediately on attaching - as a way of sort of priming any state that depends on the binding. If I have o1 and o2 and I want them to stay in sync one way - if I attach an observer to o1, I might want it to immediately fire with all of the current values of o1 so that o2 is up to date. I find there are many cases where one is better than the other so this is nice to be configurable. A way of making a block of changes atomically, so that multiple changes to the same object can be performed without firing callbacks, and then firing Callbacks will never fire synchronously. All changes within a given unit are done atomically and observers are notified after this. In the browser context, a unit will most often be a single event handler. When the event handler exits, observers will be delivered change records. the callbacks at the end. This can be important for ensuring a consistent state before any observer callbacks fire. Alternatively to creating some kind of block, it would be powerful to have the option of tying the callbacks to the event loop - I believe this is what ember.js does, though I'm sure it could be done a lot more efficiently natively. This is something that the proposal intentionally is not covering. The idea is that [[DeliverAllChangeRecords]] would be called be the embedder at the end of microtask which. Rafael spent a lot of time getting the timing of DOM mutation observer callbacks right so I'm sure he can provide more details. http://www.whatwg.org/specs/web-apps/current-work/#perform-a-microtask-checkpoint -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss