Re: generators vs forEach
I thought about yield* but it was not available at the time I wrote this. But it does not fit the bill because it deals with the synchonous part of the generator dance, not the async part. My run loop is if a bit more than the yield* loop (but not much more). The differences are the tests that deal with the PENDING case ( https://github.com/bjouhier/galaxy/blob/master/lib/galaxy.js lines 83 and 88). I'm not using Q. I wanted to have minimal runtime overhead so I designed it so that it does not allocate any extra objects. It's all done with a simple loop. 2013/7/16 Ron Buckton rbuck...@chronicles.org I assume you are referring to something like Q.async/Q.spawn to turn the generator into an async function using promises? Sent from my Windows Phone -- From: Ron Buckton rbuck...@chronicles.org Sent: 7/15/2013 5:02 PM To: Bruno Jouhier bjouh...@gmail.com; es-discusses-discuss@mozilla.org Subject: RE: generators vs forEach Bruno, wouldn't yield* work here to delegate the inner yields? Sent from my Windows Phone -- From: Bruno Jouhier bjouh...@gmail.com Sent: 7/15/2013 4:12 PM To: es-discuss es-discuss@mozilla.org Subject: Re: generators vs forEach There is no need to CPS transform functions and there is no need for deferred functions either. It can all be done with today's generators and a little helper library. With the C# async/await notation: - The yield keyword is your await keyword. - The little * in function* is your async keyword. With this you can write: function* asyncEach(array, fn) { for (var i = 0; i array.length; i++) yield fn(array[i], i); } and you can call it as: function* myFunc(array) { yield asyncEach(array, function*(elt, i) { var foo = yield asyncBar(elt); // more ... }) } Note that there is *no* helper API in all these async functions that call other async functions; The helper API is only needed to interface this with the classical callback world: at the very bottom of the stack when you call low level callbacks-based I/O functions, and at the top of the stack when the event loop runs one of your generator functions. The trick is that you need a clever run function to do the little yield/next dance with generator functions that call other generator functions. I've implemented this in https://github.com/bjouhier/galaxy/blob/master/lib/galaxy.js (the run and invoke functions) The only thing I don't like about it is the awkward syntax: - yield precedence does not work well - yield is prefix, which does not chain well - and yield is heavy anyway In short, this is a hack to get going but I'm still waiting for the full concurrency proposal and its awesome ! syntax. Bruno Consider the following: function* yieldEach(array){ array.forEach(n = { yield n; }); } In order for this to work, not only does `yieldEach` have to be suspended for the inner yield, but forEach does as well. That means CPS transforming functions based on whether they call a yielding function. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Array.prototype.find() (and probably findIndex()) compatibility hazard
I forgot to follow up on this: the issue in Asana was fixed on their side last week. We haven't received any other reports of sites these methods are causing issues for, so it's looking pretty good so far. On Fri, Jul 5, 2013 at 8:38 PM, Till Schneidereit t...@tillschneidereit.net wrote: On Fri, Jul 5, 2013 at 6:53 PM, Rick Waldron waldron.r...@gmail.comwrote: On Thu, Jul 4, 2013 at 8:13 PM, Till Schneidereit t...@tillschneidereit.net wrote: Just as with the recent addition of Array.prototype.values(), we're running into problems with Array.prototype.find()[1]. Asana uses an internal framework called Luna that contains an IIterable. This defines[2][3], among others, `find` and `findIndex` functions with signatures that aren't compatible with the ones specified in ES6. That causes the entire application to not work. At all. I'll try contacting Asana in the hope of them fixing the issue, but this'll probably not be the last issue with `find`. [1]: https://bugzilla.mozilla.org/show_bug.cgi?id=890070 [2]: https://d3ki9tyy5l5ruj.cloudfront.net/prod/build/bundles/5e40e508ea86bea48248afec47fb23f8f1100243/apps/asana/bundle.js?cb=1372896568000, lines 3030 - 3044 [3]: https://gist.github.com/anonymous/84cde557147d24a2 (in case the original link changes) Thanks for the report! I'm also seeing: - filter - forEach - indexOf - join - map - reduce (From L3024-3074) It appears that an IIterable is used to create the IVector, which then has its patchClass method called with (built-in) Array (L3205). The patchClass operation is then extending the Array.prototype with all of the custom methods. I've reduced it from the provided code: https://gist.github.com/rwldrn/2864ff4b3f804005f370 Ah, great, thanks for doing that! The reduced version confirms what I thought was going on: `patchClass`, `patchInstance` and `addToClass` all only add the given function to the given target if a same-named function doesn't already exist. As the other potentially-replaces functions all predate the library, their semantics match. I'm confident this can be fixed internally with little to no problem (assuming they have adequate tests written to support their codebase) I very much agree, yes. We only had this in Nightly builds for about a week now, but it's somewhat reassuring that, as of yet, this is the only issue we're aware of with `find` and `findIndex`. till Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Array.prototype.find() (and probably findIndex()) compatibility hazard
On Tue, Jul 16, 2013 at 5:39 AM, Till Schneidereit t...@tillschneidereit.net wrote: I forgot to follow up on this: the issue in Asana was fixed on their side last week. We haven't received any other reports of sites these methods are causing issues for, so it's looking pretty good so far. Great news! Thanks for the update :) Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: How primitive are Symbols? Bignums? etc
On Jul 15, 2013, at 10:30 PM, Brendan Eich wrote: Axel Rauschmayer wrote: The (x === Object(x)) test evaluates to true for value objects in this proposal, though. This may break code looking for primitives but we need to see what such code expects. Is it filtering out the legacy typeof-result primitives (plus null), trying to find values for which typeof currently returns object or function? If so, I don't see a problem: int64, bignum, etc. are not legacy primitives. Is this test looking for objects that are their own wrappers? Again all is well, unless mutable wrapper is assumed -- but that's not safe in the ES5 era to assume, anyway. The most frequent use case I’ve encountered: does the value have a prototype (i.e., will Object.getPrototypeOf() work)? I’m assuming that value objects will have a prototype, accessible via Object.getPrototypeOf (?) Yes, they are after all value objects :-P. js Object.getPrototypeOf(0UL) 0UL In the latest spec. draft, Object.getPrototypeOf(new Symbol) returns null because that is what the [[GetInheritance]] MOP operation produces for exotic symbol objects. That's because symbols symbols aren't supposed to have any observable properties. [[GetInhertance]] would do something else for value objects that actually exposed inherited properties. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: How primitive are Symbols? Bignums? etc
Allen Wirfs-Brock wrote: On Jul 15, 2013, at 10:30 PM, Brendan Eich wrote: Axel Rauschmayer wrote: The (x === Object(x)) test evaluates to true for value objects in this proposal, though. This may break code looking for primitives but we need to see what such code expects. Is it filtering out the legacy typeof-result primitives (plus null), trying to find values for which typeof currently returns object or function? If so, I don't see a problem: int64, bignum, etc. are not legacy primitives. Is this test looking for objects that are their own wrappers? Again all is well, unless mutable wrapper is assumed -- but that's not safe in the ES5 era to assume, anyway. The most frequent use case I’ve encountered: does the value have a prototype (i.e., will Object.getPrototypeOf() work)? I’m assuming that value objects will have a prototype, accessible via Object.getPrototypeOf (?) Yes, they are after all value objects :-P. js Object.getPrototypeOf(0UL) 0UL In the latest spec. draft, Object.getPrototypeOf(new Symbol) returns null because that is what the [[GetInheritance]] MOP operation produces for exotic symbol objects. That's because symbols symbols aren't supposed to have any observable properties. [[GetInhertance]] would do something else for value objects that actually exposed inherited properties. As it should: js Object.getPrototypeOf(0UL) === uint64.prototype true for toString and valueOf at least. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: How primitive are Symbols? Bignums? etc
On Jul 16, 2013, at 4:34 AM, Andreas Rossberg wrote: On 15 July 2013 19:44, Allen Wirfs-Brock al...@wirfs-brock.com wrote: The is primarily an internal spec. change. Many internal operations within the spec. require objects as parameters. This required inserting inserting explicit guards in p=many places within the specification and remembering to include them in new algorithms. At the March meeting you objected to the two pages of specification required to define Symbols as exotic objects. It turned out that those two pages were fair simpler and less intrusive than the all the individual spec. changes (and ongoing additions) that were needed to support symbols as primitive values. I'm afraid I still don't see how this is the case (the draft diffs are not particularly easy to read). Almost everything should be handled by ToObject creating a wrapper object in the traditional places, shouldn't it? What are the contexts where (a) an object is required, but (b) a symbol would behave differently from existing primitives? User visible semantics comes down to whether or not there is a Symbol wrapper object. As far as I can tell, tell from the notes, there was no consensus WRT Symbol wrappers record in March and when I tried to convert to Symbols as primitive values in the spec. I don't provide such wrappers. Instead, I made ToObject throw for symbols values. OK, that might explain the difficulty you faced. My understanding of the March agreement certainly was that there is a wrapper object, consistent with other primitive types. And I'm pretty sure that that makes the spec quite simple and regular. Yes, wrappers would make it easier, but my take away from the meeting and subsequent discussion was that we didn't want to add any more observable wrappers. We really should avoid adding new primitive types and wrapper objects. Value objects are the way to go, starting with Symbol. I'd argue for the contrary, namely that we should avoid artificially cramping more inappropriate concepts into the notion of 'object'! These are not objects by any useful definition of the word, despite the MOP being rich enough to support them as degenerate cases. Clearly I disagree. In ES and other polymorphic object-based languages, objects are really the basis for uniformity of references. Any abstraction can be represented as an object and any operation can be manifested as method invocations upon an object. It is the ES primitive types that introduce non-uniformity that either needs to be special cased or partially hidden behind hacks such as automatic conversion to wrapper objects. Clearly at an implementation level you want to have optimized representations of certain kinds of entities. You can get there two different ways. You can expose the optimized representation as primitive types that requires user level special casing or you can uniformly expose everything as an object and let the implementation opaquely use special case representations where it suits it. It seems clear to me, that if you want to support an open ended set of new abstractions you need to go the uniform objects route. We're stuck with numbers, strings, and booleans and their corresponding wrappers. We don't need more special cases at that level. I'd be interested in hearing how this makes any difference to you from an implementation perspective. Even when symbols are specified as exotic objects you can still encode them as immediate values, just like you would a SmallInteger in Smalltalk. It's only when actual object MOP operations are applied to them that you should have to do any special casing but these are generally the same situations where you would have to auto-wrap primitive values. The difference is that with real primitives + wrapper objects every respective operation has a single place where it does the ToObject conversion (which exists already), and downstream you can easily make it an invariant that what you've got is an ordinary object with an ordinary object representation. No special casing required. If, on the other hand, you make new primitives pseudo-objects, but still want to represent them efficiently, then all parts that deal with objects now also have to deal with those denormal representations. You say only actual MOP operations, but surely there are several times more occurrences of those than of ToObject. It involves the majority of language operations, and in contemporary implementations, every one of them potentially has a dozen or more possible implementations. Sounds like your are concerned about special casing MOP dispatches on primitives representations. A good concern. However, I don't actually see much benefit of a primitive non-dispatchable representation for symbols and if you do, you could still hide it in ToObject. Nothing saying you can't have internal wrapper objects and be careful not to
Re: generators vs forEach
// this doesn't work function* generator(){ [1,2,3].forEach( function(x){ yield x } ) } This would make generators deep, violating the non-interleaving assumptions of intermediate callers on the call stack. This is why we accepted generators only on condition that they be shallow. We knew at the time that this privileges built-in control structures over user defined ones. The alternative would have been to omit generators completely. We agree that shallow generators were worth it, despite this non-uniformity. While I understand the compromise, and the wish to get in some form of generators anyway, the discrimination against user-defined control structures troubles me deeply. It introduces a new language construct that defies abstraction. It means that we can no longer use functional abstraction freely, but have to worry about interactions with generators. For the specific case of forEach et al, another way to avoid intermediate stack frames would be guaranteed inlining. If we always inline .forEach before execution, then specialize the resulting code wrt the callback, any yields in the callback would be directly in the caller. Consider this chain of code transformations: // inline forEach; this still doesn't work function* generator(){ (function forEach(arr,cb) { for (var i=0; iarr.length; i++) cb(arr[i]); })([1,2,3], function(x){ yield x } ); } // instantiate inlined forEach; still doesn't work function* generator(){ let arr = [1,2,3]; let cb = function(x){ yield x }; for (var i=0; iarr.length; i++) cb(arr[i]); } // inline cb; still doesn't work function* generator(){ let arr = [1,2,3]; for (var i=0; iarr.length; i++) (function(x){ yield x})(arr[i]); } // instantiate inlined cb; this should work function* generator(){ let arr = [1,2,3]; for (var i=0; iarr.length; i++) yield arr[i]; } If such inlining and instantiating functions in ES6 changes the validity of code, then the opposite path -building abstractions from concrete code examples- is also affected. I find that worrying. The final form of the code can be handled with shallow generators, and it should be semantically equivalent to the initial form (just function application and variable instantiation in between). So why shouldn't both forms be valid and doable without overcomplicating the shallow generator ideal? In pragmatic terms, perhaps introducing inline annotations for operations like .forEach and for their callback parameters could avoid nested stack frames her without forcing user-side code duplication. Such annotation-enforced inlining should also help with performance of .forEach et al (currently behind for-loops). [in conventional pre-compiling FPL implementations, such worker/ wrapper staging plus inlining is done at compile time (stage recursive higher-order function into non-recursive wrapper and recursive but not higher-order worker; inline wrapper to instantiate the functional parameters in the nested worker; finally apply standard optimizer); it is an easy way to avoid deoptimizations caused by higher-order parameters interfering with code analysis; provided the library author helps with code staging and inline annotations ] Put another way, shallow generators are equivalent to a local cps transform of the generator function itself. Deep generators would require the equivalent of CPS transforming the world -- violating the stateful assumptions of existing code. FYI: I'm not sure what you mean by violating the stateful assumptions but there is an even more local transform than that for ES6 generators: writing code in monadic style always captures the local continuation only. That allows for generator monads that compose those local continuations back together. An example of such a generator monad can be found here (using a list of steps for simplicity; code is TypeScript v0.9, to make use of ES6 classes with class-side inheritance and arrow functions) https://gist.github.com/clausreinke/5984869#file-monadic-ts-L91-L125 with example code (using user-defined forOf) at https://gist.github.com/clausreinke/5984869#file-monadic-ts-L492-L529 This differs from ES6 generators in using a functional API (next returns {done,value,next}) and in building on expressions and user-defined control-flow operations instead of statement blocks and built-in control-flow structures. Still, this style does seem to allow more reuse of existing ES5 array operations than ES6 generators will, as this small example demonstrates: console.log(\n// mixing yield with higher-order array ops (prefix ^)); var generator4 = ()= [1,2,3].map( x= G.yield(x) ) .reduce( (x,y)= x.then( _= y ), G.of(undefined) ) ; MonadId.forOf( generator4(), y= (console.log(^ +y), MonadId.of(y)) ); append example to the end of that gist, execute with tsc -e (TS v0.9 required,
Re: generators vs forEach
Mark S. Miller wrote: On Tue, Jul 16, 2013 at 10:54 AM, Claus Reinke claus.rei...@talk21.com mailto:claus.rei...@talk21.com wrote: // this doesn't work function* generator(){ [1,2,3].forEach( function(x){ yield x } ) } This would make generators deep, violating the non-interleaving assumptions of intermediate callers on the call stack. This is why we accepted generators only on condition that they be shallow. We knew at the time that this privileges built-in control structures over user defined ones. The alternative would have been to omit generators completely. We agree that shallow generators were worth it, despite this non-uniformity. While I understand the compromise, and the wish to get in some form of generators anyway, the discrimination against user-defined control structures troubles me deeply. Troubles me too. As of ES6 the only possible alternative would be to remove generators from the language. I can't see that happening. That would be somewhere between making the perfect the enemy of the good and cutting off your nose to spite your face. If we want call/cc (plus macros to sugar it into usability), there's the door -- it ain't in JS outside of Rhino, and (for good reasons you adduce) it won't be added. But we have good use cases for generators, including to implement iterators independent of async. programming. For async we're looking at defer/await for ES7. This is how living languages evolve. Sorry to preach to the choir (I hope :-P). /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: generators vs forEach
Le 16/07/2013 19:54, Claus Reinke a écrit : // this doesn't work function* generator(){ [1,2,3].forEach( function(x){ yield x } ) } I have been thinking and with for..of, I can't find a good reason to use .forEach instead of for..of. for..of does what you need here with generators too. This would make generators deep, violating the non-interleaving assumptions of intermediate callers on the call stack. This is why we accepted generators only on condition that they be shallow. We knew at the time that this privileges built-in control structures over user defined ones. The alternative would have been to omit generators completely. We agree that shallow generators were worth it, despite this non-uniformity. While I understand the compromise, and the wish to get in some form of generators anyway, the discrimination against user-defined control structures troubles me deeply. It introduces a new language construct that defies abstraction. It means that we can no longer use functional abstraction freely, but have to worry about interactions with generators. For the specific case of forEach et al What do you mean by et al? I don't believe .map, .reduce or .filter are any interesting to use alongside generators. Even if so, for..of can work too and is decently elegant (YMMV): function* g(){ [1,2,3].map(x = {yield transform(x)}) } becomes function* g(){ for(x of [1,2,3]) yield transform(x); } David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
[Resurrection] Make Function.length Configurable
This is a resurrection of an earlier proposal from Nathan Wall [1], that would make Function.length configurable. The initial proposal was to make it writable, but configurable instead was suggested by Claude Pache [2]. Nathan's original post [1] does a good job of outlining the motivation, so I won't reiterate them here. From what I can gather, making Function.length configurable seemed to receive a positive response [3] [4] [5], but the thread apparently died. Perhaps I just need to find a new API paradigm, but I run into this issue on a regular basis writing callback utilities, and would be very interested in seeing this move forward. For convenience, the Function.length spec from the latest draft [6]: This is a data property with a value of 1. This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }. [1] http://www.mail-archive.com/es-discuss@mozilla.org/msg21786.html [2] http://www.mail-archive.com/es-discuss@mozilla.org/msg21792.html [3] http://www.mail-archive.com/es-discuss@mozilla.org/msg21793.html [4] http://www.mail-archive.com/es-discuss@mozilla.org/msg21794.html [5] http://www.mail-archive.com/es-discuss@mozilla.org/msg21795.html [6] http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.3.2.2 Thanks, -- Jeremy Martin 661.312.3853 http://devsmash.com @jmar777 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: [Resurrection] Make Function.length Configurable
I referenced Function.length instead of Function#length. Here's the actually relevant spec [1]: The value of the length property is an integer that indicates the typical number of arguments expected by the function. However, the language permits the function to be invoked with some other number of arguments. The behaviour of a function when invoked on a number of arguments other than the number specified by its length property depends on the function. This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }. Everything else still applies. (Hopefully) goes without saying, but the same should apply to GeneratorFunction instances as well [2]. [1] http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.3.4.1 [2] http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.19.3.4 On Tue, Jul 16, 2013 at 3:53 PM, Jeremy Martin jmar...@gmail.com wrote: This is a resurrection of an earlier proposal from Nathan Wall [1], that would make Function.length configurable. The initial proposal was to make it writable, but configurable instead was suggested by Claude Pache [2]. Nathan's original post [1] does a good job of outlining the motivation, so I won't reiterate them here. From what I can gather, making Function.length configurable seemed to receive a positive response [3] [4] [5], but the thread apparently died. Perhaps I just need to find a new API paradigm, but I run into this issue on a regular basis writing callback utilities, and would be very interested in seeing this move forward. For convenience, the Function.length spec from the latest draft [6]: This is a data property with a value of 1. This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }. [1] http://www.mail-archive.com/es-discuss@mozilla.org/msg21786.html [2] http://www.mail-archive.com/es-discuss@mozilla.org/msg21792.html [3] http://www.mail-archive.com/es-discuss@mozilla.org/msg21793.html [4] http://www.mail-archive.com/es-discuss@mozilla.org/msg21794.html [5] http://www.mail-archive.com/es-discuss@mozilla.org/msg21795.html [6] http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.3.2.2 Thanks, -- Jeremy Martin 661.312.3853 http://devsmash.com @jmar777 -- Jeremy Martin 661.312.3853 http://devsmash.com @jmar777 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: How primitive are Symbols? Bignums? etc
Allen Wirfs-Brock wrote: We're stuck with numbers, strings, and booleans and their corresponding wrappers. We don't need more special cases at that level. I should write an apologator (http://www-archive.mozilla.org/apology.html) for inflicting primitives as non-objects in those ten days in May. Agree they are an anti-pattern at this point, not to be imitated by symbol/Symbol (and I thought TC39 agreed on this, and no strawman or proposal had both). For symbols you don't inherently have to have two different representations. Not only do you, or we, not face _a priori_ arguments for symbol and Symbol, users do not want. Yes, it's drawing a line and saying no added special case primitive types and no new wrapper objects. Starting with ES6 all new abstractions can be conceptualized as objects. Agreed. Not to dogpile on, but just to apologize for primitives and say that they are the exception that proves the rule, not the pattern for novelties. See also int64, bignum, etc. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Language Negotiation API
On Tue, 16 Jul 2013, Andy Earnshaw wrote: navigator.language isn't part of any stable specification It's part of the HTML standard: http://whatwg.org/html/#language-preferences ...which is very stable at this point (there's basically no way that part of the spec can change in an incompatible fashion, since it's widely implemented; the only possible changes are those that approach reality more, and those that add features). and even the current HTML 5.1 draft doesn't specify that tags should be returned in canonical form. Do you think it would be a good idea to raise an issue for this? Fixed. (A change that approaches reality more.) -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.' ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Map etc and [[Call]]
All of the new constructors, Map, Set, WeakMap and WeakSet should fail when called as a function unless `this` already has a certain internal property, ie [[MapData]]. This is so that sub classing works as expected. However, all JS engines that supports Map, Set and WeakMap are future hostile and they all return a new instance when called as a function. For example, here is the V8 code: function MapConstructor() { if (%_IsConstructCall()) { %MapInitialize(this); } else { return new $Map(); } } I understand that fully supporting @@create requires a lot of work but until then we should at least throw when called as function to allow us to get out of this mess eventually. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Creating your own errors
On Wed, Jul 10, 2013 at 11:49 PM, Mark S. Miller erig...@google.com wrote: Hi Jonas, The perpetual hazard with trying to clean things up is, of course, legacy compat constraints. Regarding ES itself, many of those on this list (including myself) feel oriented about when and where these bite and how much, and have successfully navigated through these to many successful cleanups. We have also succeeded at not wasting too much time on attractive cleanups whose adoption was doomed because of these constraints. Regarding DOM, I am certainly less oriented and I suspect at least some others on this list are too. In the absence of knowledge, it is tempting to imagine the worst and despair of cleaning up anything that is already deployed. Could you give a summary -- necessarily subjective which is fine -- of how you think about what can and cannot be successfully cleanup up here? Thanks. I think we have the following constraints for exceptions thrown by the DOM: x instanceof DOMException This *probably* needs to evaluate to true. x.code == DOMException.HIERARCHY_REQUEST_ERR x.code == 3 This definitely needs to evaluate to true for a bunch of older APIs. This used to be the only way to test what type of exception you had. For newer exception types we haven't added a code and so .code returns 0. For those APIs you use .name instead, see below. Obviously the exact constant and number varies with the exception type. x.name == HierarchyRequestError This should test true. This should be uncontroversial enough that I don't think it matters how much dependency there is, right? Obviously the exact value varies with the exception type. x.message This probably needs to contain a human readable error message. This should be uncontroversial enough that I don't think it matters how much dependency there is, right? Object.toString(x) I *don't* think it's important what this returns. I.e. I would guess that we can safely subclass DOMException as needed. I think we have the following constraints for properties that contain error information in APIs that currently use DOMError (IDBTransaction.error in the IndexedDB spec for example). x instanceof DOMError Probably doesn't matter what this returns. x.name = AbortError This should be uncontroversial enough that I don't think it matters how much dependency there is, right? x.message This probably needs to contain a human readable error message. This should be uncontroversial enough that I don't think it matters how much dependency there is, right? Object.toString(x) Probably doesn't matter what this returns. I doubt that in either case it matters if these properties live on the objects themselves, or on the prototype chain. So all in all, I think we have a lot of room for what to do in both cases. The only requirements is that exceptions *likely* need to test true for instanceof DOMException, and that they in some cases need to have a specific numeric code property. My recommendation would be to * Get rid of DOMError and use DOMException in its place * Add new subclasses for each exception type. I.e. exceptions with .name == HierarchyRequestError should also test true for instanceof HierarchyRequestError * Keep specifying that DOMException is a subclass of Error. This is already the case, but I wanted to make it clear that this shouldn't change. I personally think that the second bullet is a bit silly. But since that appears to be the convention that ES uses then we should stick with it. / Jonas On Wed, Jul 10, 2013 at 8:31 PM, Jonas Sicking jo...@sicking.cc wrote: On Jul 10, 2013 3:49 PM, Erik Arvidsson erik.arvids...@gmail.com wrote: Jonas, DOM never throws DOMError. DOMErrors are used for other error mechanisms, such as callbacks. [1] Indeed. But this is one of the things I'm trying to fix. It seems very silly that the DOM defines two classes of error objects. Neither of which are following the patterns used by ES. / Jonas The DOM spec does however throw DOMException objects [2]. These are instanceof Error (see WebIDL [3]) var ex; try { document.appendChild(document); } catch (e) { ex = e; } assert(ex instanceof Error); assert(ex.contructor === DOMException); assert(ex.name === 'HierarchyRequestError'); In Blink DOMException also have a stack property assert(stack in ex); [1] http://dom.spec.whatwg.org/#interface-domerror [2] http://dom.spec.whatwg.org/#exception-domexception [3] http://dev.w3.org/2006/webapi/WebIDL/#es-exception-interface-prototype-object On Wed, Jul 10, 2013 at 3:02 PM, Jonas Sicking jo...@sicking.cc wrote: On Wed, Jul 10, 2013 at 12:52 PM, Domenic Denicola dome...@domenicdenicola.com wrote: Woah, François, that seems pretty overcomplicated; why not replace everything inside the constructor with `this.message = message`? It has the same effect in the browsers I've seen. (Also don't forget `SomeError.prototype.constructor = SomeError`.)
Re: Map etc and [[Call]]
On Tue, Jul 16, 2013 at 7:10 PM, Erik Arvidsson erik.arvids...@gmail.comwrote: All of the new constructors, Map, Set, WeakMap and WeakSet should fail when called as a function unless `this` already has a certain internal property, ie [[MapData]]. This is so that sub classing works as expected. However, all JS engines that supports Map, Set and WeakMap are future hostile and they all return a new instance when called as a function. For example, here is the V8 code: function MapConstructor() { if (%_IsConstructCall()) { %MapInitialize(this); } else { return new $Map(); } } I understand that fully supporting @@create requires a lot of work but until then we should at least throw when called as function to allow us to get out of this mess eventually. It's painful, but I agree. This will prevent a build up of incorrect code that may hold @@create semantics hostage. Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: generators vs forEach
On Tue, Jul 16, 2013 at 3:45 PM, David Bruant bruan...@gmail.com wrote: Le 16/07/2013 19:54, Claus Reinke a écrit : // this doesn't work function* generator(){ [1,2,3].forEach( function(x){ yield x } ) } I have been thinking and with for..of, I can't find a good reason to use .forEach instead of for..of. for..of does what you need here with generators too. I've been looking at this example and thinking the same thing. Additionally, I'm curious to know what this would've looked like without being a contrived example of mis-used yield, considering Array.prototype.forEach returns undefined and the callback returns undefined as well (regardless of whether or not user code specifies a return). Rick This would make generators deep, violating the non-interleaving assumptions of intermediate callers on the call stack. This is why we accepted generators only on condition that they be shallow. We knew at the time that this privileges built-in control structures over user defined ones. The alternative would have been to omit generators completely. We agree that shallow generators were worth it, despite this non-uniformity. While I understand the compromise, and the wish to get in some form of generators anyway, the discrimination against user-defined control structures troubles me deeply. It introduces a new language construct that defies abstraction. It means that we can no longer use functional abstraction freely, but have to worry about interactions with generators. For the specific case of forEach et al What do you mean by et al? I don't believe .map, .reduce or .filter are any interesting to use alongside generators. Even if so, for..of can work too and is decently elegant (YMMV): function* g(){ [1,2,3].map(x = {yield transform(x)}) } becomes function* g(){ for(x of [1,2,3]) yield transform(x); } David __**_ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Map etc and [[Call]]
Brandon Benvie wrote: On 7/16/2013 4:10 PM, Erik Arvidsson wrote: All of the new constructors, Map, Set, WeakMap and WeakSet should fail when called as a function unless `this` already has a certain internal property, ie [[MapData]]. This is so that sub classing works as expected. However, all JS engines that supports Map, Set and WeakMap are future hostile and they all return a new instance when called as a function. For example, here is the V8 code: function MapConstructor() { if (%_IsConstructCall()) { %MapInitialize(this); } else { return new $Map(); } } I understand that fully supporting @@create requires a lot of work but until then we should at least throw when called as function to allow us to get out of this mess eventually. I wonder if the current spec language is a remnant of before @@create was added to the spec. It should be possible to detect when the constructors are called with a receiver that is not an initializing instance and simply create a new instance. Pseudo code: function Map(...args){ if (!IsObject(this) || !%HasMapData(this)) { // got a primitive, the global object, or some random object like from `Map.call({})` return new Map(...args); } else if (!%IsInitializedMap(this)) { Nit: else after return ;-). More substantive: Mark's suggestion seems better because it throws on random wrong this but supports strict calls by unqualified name. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Creating your own errors
On Tue, Jul 16, 2013 at 4:30 PM, Jonas Sicking jo...@sicking.cc wrote: Object.toString(x) I assume you mean Object.prototype.toString.call(x) I *don't* think it's important what this returns. I.e. I would guess that we can safely subclass DOMException as needed. I think we have the following constraints for properties that contain error information in APIs that currently use DOMError (IDBTransaction.error in the IndexedDB spec for example). x instanceof DOMError Probably doesn't matter what this returns. FWIW, Neither Blink nor WebKit exposes DOMError so this should be safe to change (on the open web at least). x.name = AbortError This should be uncontroversial enough that I don't think it matters how much dependency there is, right? x.message This probably needs to contain a human readable error message. This should be uncontroversial enough that I don't think it matters how much dependency there is, right? Object.toString(x) Probably doesn't matter what this returns. I doubt that in either case it matters if these properties live on the objects themselves, or on the prototype chain. So all in all, I think we have a lot of room for what to do in both cases. The only requirements is that exceptions *likely* need to test true for instanceof DOMException, and that they in some cases need to have a specific numeric code property. My recommendation would be to * Get rid of DOMError and use DOMException in its place * Add new subclasses for each exception type. I.e. exceptions with .name == HierarchyRequestError should also test true for instanceof HierarchyRequestError * Keep specifying that DOMException is a subclass of Error. This is already the case, but I wanted to make it clear that this shouldn't change. I personally think that the second bullet is a bit silly. But since that appears to be the convention that ES uses then we should stick with it. Agreed. There will be issues here since DOM has throw a SyntaxError, which means throw a DOMException with the name SyntaxError and the code DOMException.SYNTAX_ERR so that would mean that we have a naming conflict since ES already have a SyntaxError constructor. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Map etc and [[Call]]
Mark S. Miller wrote: On Tue, Jul 16, 2013 at 4:56 PM, Brendan Eich bren...@mozilla.com mailto:bren...@mozilla.com wrote: More substantive: Mark's suggestion seems better because it throws on random wrong this but supports strict calls by unqualified name. Nit: All calls. The non-coercion of |this| depends only on the strictness of the callee, not the caller. Oh right, and Map, etc. are built-in so as-if-self-hosted-strict in this regard. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Map etc and [[Call]]
On Jul 16, 2013, at 4:10 PM, Erik Arvidsson wrote: All of the new constructors, Map, Set, WeakMap and WeakSet should fail when called as a function unless `this` already has a certain internal property, ie [[MapData]]. This is so that sub classing works as expected. Yes, indeed: let m = map(); //I think m is a map is specified as throwing a TypeError. To implement it otherwise is diverging from the spec. Using constructors as callable factories is pretty hostile to subclasses that need to do super calls to superclass constructors. While it is possible to carefully code a constructor function that it can work as both a factory and an initializer there are plenty of subtleties (and/or performance traps) that are likely to trip-up everyday JS programmers. For that reason, I expect that callable constructors that allocate is going to be quickly identified as a ES6 anti-pattern. The natural thing to do with ES6 classes is to always use new and to code the constructor function to only act as an instance initializer. In support of that pattern, Map and friends only allocated when invoked via new. We will be talking about this some more at next week's TC39 meeting. However, all JS engines that supports Map, Set and WeakMap are future hostile and they all return a new instance when called as a function. For example, here is the V8 code: function MapConstructor() { if (%_IsConstructCall()) { %MapInitialize(this); } else { return new $Map(); } } Yes, this is wrong because if this was super called from a subclass constructor it would return a new Map instance to the subclass constructor rather than initializing (if possible) the subclass provided instance as Map. I'd don't know much about the V8 self-hosting mechanism, but it looks to me like it should be sufficient to code this as: function MapConstructor() { %MapInitialize(this); } assuming that %MapInitialize is smart enough to throw on undefined and other this values that are not appropriate to initialize as Maps. I understand that fully supporting @@create requires a lot of work but until then we should at least throw when called as function to allow us to get out of this mess eventually. For background here is how new Foo() is now supposed to work: let newObj = Foo[@@create](); //allocate an initialized Foo instance. Foo.call(newObj); //initialize the newObject ) It's not very complicated. Allen -- erik ___ 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: Map etc and [[Call]]
On 7/16/2013 4:56 PM, Brendan Eich wrote: Mark's suggestion seems better because it throws on random wrong this but supports strict calls by unqualified name. I don't think that it'd be nice if `Map()` could throw or not throw depending on strictness of the caller. Working around that requires something like: function Map(...args){ if (this === undefined || this === %CallerGlobal()) { return new Map(...args); } else if (!%HasMapData(this)) { throw new TypeError(Not a Map); } else if (%HasInitializedMapData(this)) { throw new TypeError(Map is already initialized); } %MapInitialize(this); } (V8's implementation is also incorrect in that it doesn't throw when you do `Map.call(new Map)`) (so is SM's) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Map etc and [[Call]]
On 7/16/2013 5:09 PM, Mark S. Miller wrote: Nit: All calls. The non-coercion of |this| depends only on the strictness of the callee, not the caller. Ah yes, right! Nevermind on the complaint in my last message. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Map etc and [[Call]]
I completely agree with you Allen. new-less construct is an anti pattern. On Tue, Jul 16, 2013 at 5:13 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: I understand that fully supporting @@create requires a lot of work but until then we should at least throw when called as function to allow us to get out of this mess eventually. For background here is how new Foo() is now supposed to work: let newObj = Foo[@@create](); //allocate an initialized Foo instance. Foo.call(newObj); //initialize the newObject ) It's not very complicated. The semantics and the spec are simple but... ...it does require support for symbols, shared symbols between realms, updates to new without any perf regression. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Map etc and [[Call]]
On Jul 16, 2013, at 4:41 PM, Mark S. Miller wrote: I like the general idea. But when actually called simply as a function, this would be unpleasant. Understanding that any ES5 behavior will be a compromise to prepare the ground for ES6, I suggest this variant: function MapConstructor() { if (%_IsConstructCall()) { %MapInitialize(this); } else if (this === void 0) { this test isn't sufficient is you really want to support constructors as callable factories. Consider an namespace object (or a module) such as: let ES6 = {Map, WeakMap, Set}; ES6.Map(); return new $Map(); } else { throw ; } } I already have a lot of code that simply calls WeakMap() without saying new. I suspect that others will too by the time they see v8's new built-in WeakMaps. We need to discourage leaving out the new, rather than trying to preserve the small amount (in terms of web scale) of existing code that uses Map/Set/WeakMap as callable factories. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
12[__proto__]
All current engines I could try return Number.prototype for: 12[__proto__] But the new spec says this should be a TypeError. It's more consistent with the other members of Object.prototype to do an implicit ToObject here, and apparently matches existing implementations. Is it intentional that the spec is treating this as a TypeError? Luke ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: 12[__proto__]
All current engines I could try return Number.prototype for: 12[__proto__] But the new spec says this should be a TypeError. What is the relevant part of the new spec? In B.2.2.1, step #2 throws a TypeError instead of doing a ToObject. get Object.prototype.__proto__ The value of the [[Get]] attribute is a built-in function that requires no arguments. It performs the following steps: 1. Let O be the this value. 2. If Type(O) is not Object, then throw a TypeError exception. 3. Return the result of calling the [[GetInheritance]] internal method of O. It's more consistent with the other members of Object.prototype to do an implicit ToObject here, and apparently matches existing implementations. Is it intentional that the spec is treating this as a TypeError? Luke ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: 12[__proto__]
On Jul 16, 2013, at 6:33 PM, Luke Hoban wrote: All current engines I could try return Number.prototype for: 12[“__proto__”] But the new spec says this should be a TypeError. It’s more consistent with the other members of Object.prototype to do an implicit ToObject here, and apparently matches existing implementations. Is it intentional that the spec is treating this as a TypeError? Well, it was intentional, but perhaps wrong. As you say, the set accessor probably needs to do a ToObject. The set accessor probably only needs to do a CheckObjectCoercible followed by an immediate return if the type of this is not Object (the wrapper and hence it's modified [[Prototype]] isn't observable, so it doesn't actually need to be created). File a bug, and I'll put the revised algorithms into the ticket. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: 12[__proto__]
From: Allen Wirfs-Brock [mailto:al...@wirfs-brock.com] Sent: Tuesday, July 16, 2013 7:02 PM To: Luke Hoban Cc: es-discuss Subject: Re: 12[__proto__] On Jul 16, 2013, at 6:33 PM, Luke Hoban wrote: All current engines I could try return Number.prototype for: 12[__proto__] But the new spec says this should be a TypeError. It's more consistent with the other members of Object.prototype to do an implicit ToObject here, and apparently matches existing implementations. Is it intentional that the spec is treating this as a TypeError? Well, it was intentional, but perhaps wrong. As you say, the set accessor probably needs to do a ToObject. The set accessor probably only needs to do a CheckObjectCoercible followed by an immediate return if the type of this is not Object (the wrapper and hence it's modified [[Prototype]] isn't observable, so it doesn't actually need to be created). File a bug, and I'll put the revised algorithms into the ticket. Opened https://bugs.ecmascript.org/show_bug.cgi?id=1586. Luke ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Is Object.watch being standardizied?
And if so, where in the spec docs can I read more about it? Cheers, Behrang Saeedzadeh http://www.behrang.org ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Is Object.watch being standardizied?
On Wed, Jul 17, 2013 at 12:14 AM, Behrang Saeedzadeh behran...@gmail.comwrote: And if so, where in the spec docs can I read more about it? No, but Object.observe is: http://wiki.ecmascript.org/doku.php?id=strawman:observe Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss