Re: (Map|Set|WeakMap)#set() returns `this` ?
On Wed, Dec 5, 2012 at 10:43 PM, Rick Waldron waldron.r...@gmail.comwrote: On Wed, Dec 5, 2012 at 3:26 PM, Domenic Denicola dome...@domenicdenicola.com wrote: Readability or library preference aside, I still think it's bizarre that map.set(key, val) is analogous to (dict[key] = val, dict) and not to dict[key] = val When I'm using a fluent library like jQuery or a configuration DSL like those in the npm packages surveyed, I can see the attraction of chaining. But when I am using a basic primitive of the language, I expect uniformity across primitives. This argument won't hold when the language doesn't make any such uniformity promises, eg. array.push(val); // new length array[ array.length - 1 ] = val; // val That's just a bad analogy, because that's not what push does, since it has a variadic argument (admittedly, I don't think returning the length is useful anyway, but if it returned the value, should it return the first, last, or all of them?). And if it comes down to precedents in the language, even Array#forEach() returns undefined, contrary to popular libraries out there. Let's keep some consistency here. I agree with you, fear-driven design is bad. But don't you agree that if there's chaining, it's better done at language level rather than having all APIs be polluted by `this` returns? After all, the APIs can't guarantee a `this` return, since they might have something actually meaningful to return, otherwise we might as well just replace `undefined` with `this` as the default return value. We could introduce mutable primitives so that meaningful return values could be stored in arguments, kinda like in C, but instead of error values, we'd be returning `this`, heheheh. :) I'm curious, do you have any code examples of maps/sets that could be made clearer by chaining? Cheers, Jussi Rick ___ 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: Module Comments
On Dec 5, 2012, at 11:52 PM, Brendan Eich bren...@mozilla.org wrote: ExportDeclaration: export { ExportSpecifier (, ExportSpecifier)* } ; ExportDeclaration: export Identifier (, Identifier)* ; ExportDeclaration: export * from StringLiteral ; Reasonable point, I'll think about that. We do not so limit var, let, or const -- why should we limit export? Ok, it's a bit different (but then import is not, right?). Style enforcement should not be wired into the grammar. If I want to write export {odd, even}, {nat: naturals}; why not? Fairly agnostic about this, given that you can express most combinations within the { ... } form. But I'll think about it. Removing the curlies for this simple case would seem like a win. Another fair point. I think it might've just been a refactoring oversight. Cool, definitely want the plain identifier form, it's part of the binding (and destructuring) pattern language. Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. But that said, the convenience may well still trump the inconsistency. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Thu, Dec 6, 2012 at 8:25 AM, David Herman dher...@mozilla.com wrote: On Dec 5, 2012, at 7:16 PM, Kevin Smith khs4...@gmail.com wrote: 1) export ExportSpecifierSet (, ExportSpecifierSet)* ; This rule seems too permissive. It allows strange combinations like: export x, { y: a.b.c, z }, { j, k }, * from bloop; I think it would be better to flatten it out a little bit: ExportDeclaration: export { ExportSpecifier (, ExportSpecifier)* } ; ExportDeclaration: export Identifier (, Identifier)* ; ExportDeclaration: export * from StringLiteral ; Reasonable point, I'll think about that. 2) Do we need `export *;`? I don't see the point of exporting every declaration in the current module scope. If the programmer wants to export a bunch of stuff, the other forms make that sufficiently easy. Exporting everything encourages bad (de-modular) design. Again, reasonable point. 3) I'm just OK with as. Note that it inverts the position of the string and the binding: import { x } from goo; import ga as ga; Which makes it harder to read when you have a bunch of imports mixed together. It's harder for the eyes to scan back and forth. Yeah, that's the known downside to this syntax. We've been around this block so many times, and it's just one of those things that will end up with bikeshed colored not in paint but in blood. I'm open to alternative suggestions but not to endless discussion (it goes nowhere). The alternative of import ga = ga has the problem of looking like it's saying that ga is a string. The alternatives of import ga = module(ga) or import ga = (module ga) have the problem of making it look like the RHS is an expression. Feel free to suggest alternatives, but forgive me if I'm not willing to respond to every opinion on this one. :} Replace the current `from` form with `of` and use `from` for the single export: import go from ga; // prev: import ga as go import {a: b, b: a} of ta; // prev: import {a: b, b:a} from ta It would even make the common case shorter. :P Or keep the current `from` form and: import go off ga; // prev: import ga as go Or maybe `in`, but it sounds really weird in English as import has an implicit in. Cheers, Jussi 4) Why was this form eliminated? import x from goo; // Note lack of curlies! In an object-oriented application, we're often going to be importing a single thing (the class) from external modules. So we may see long lists like this: import { ClassA } from ClassA.js; import { ClassB } from ClassB.js; import { ClassZ } from ClassZ.js; Removing the curlies for this simple case would seem like a win. Another fair point. I think it might've just been a refactoring oversight. 5) Dynamic exports via `export = ?` could make interop with existing module systems easier. But how does that work? Basic semantics: - The module has one single anonymous export. - Clients can only get access to the export with the as form; there's no way to access it via a named export. - The value of the export is undefined until the RHS is evaluated. 6) Adding .js as the default resolution strategy: I don't think this is tenable. First, there's the practical issue of what happens when someone actually wants to load a resource without a .js extension? They change the resolution hook. Second, there's the philosophical problem of essentially setting up an alternate URL scheme. That's fine for libraries like AMD loaders or YUI. But EcmaScript is a cornerstone of the internet. External resource resolution can't conflict with HTML/CSS/etc. I'll wait till it's fleshed out more didn't last long, eh? ;-) Anyway, I don't really understand this argument but do you think there's much value to a philosophical debate on es-discuss? 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: Module Comments
Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. But that said, the convenience may well still trump the inconsistency. I think I'd prefer consistency here, as it also allows to get rid of import foo as foo; and replace it with import foo from foo; which keeps the order of import {x,y} from foo and it is all just module-level destructuring (fewer new concepts). Claus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Categorisation of ECMAScript(+event loops) Threats
Hi, This post is not intentioned to be a perfect and final guide, but rather a conversation starter. It's mostly triggered by what Andrea described as a potential attack (assigning Object.prototype.get). # Description of the JS runtime To a first approximation (ignoring things like alert/prompt and weird window resize event behaviors), a JavaScript runtime contains a heap, a call stack and a message queue. Messages accumulate in the queue and are treated one after the other. The time during which one message is treated is called a turn. Messages are queued when a user clicks and a listener listens or when a timeout fires, etc. A message contains a function which, upon being called may call other functions (hence the call stack). Functions manipulate memory, including things in the heap. The heap contains a bunch of objects being accessible either from the global object or the scope of the function being called. # Some properties ## Environment Mutability Until ES5, pretty much everything in the heap could be modified at any turn by anyone; new properties could be added/removed from the global object, or the Object.prototype object for instance. Sharing access to an object pretty much meant giving away the possibility to anyone with access to this object to mess up with it. ES5 introduces a couple of constructs like Object.preventExtensions and Object.defineProperty(,,{configurable: false, writable: true|false}) to enable a programmer to share some object but have some properties enforced. It is probably the first time there are constructs that act on objects to create permanent effects on them. ## During a turn Stating the obvious, but the function running in a turn has the power to do anything to whatever it has access to. Among the possible changes, it's possible to Object.freeze any object the function has access to. When some JS code is running during a turn, it can't be preempted by some other code. The code has to end. ## First turn There is a first turn. ## (Partial) conclusion If malicious code runs, it can do whatever is possible during its turns. The role of a defenser will be to reduce whatever is possible to nothing harmful. First reaction, if the malicious code runs first, too bad, it can edit anything in the JavaScript environment it has access to, including modifying Object.prototype. The careful attacker will freeze Object.prototype after having modified it. The opposite is true too. If the defender runs first, it can defend its environment. If the defender doesn't want Object.prototype to be modified, it can freeze it. If it wants to add polyfills then freeze everything, that's also a decent idea. If during the first turn no one modifies anything in an harmful or defensive way, the decision to attack or defend is let to the code running in the next turn and so on. # Categorisation of threats ## Threats that are unprotectable against Programming languages or APIs sometimes leave holes by design that even the most skilled programmers couldn't write defensive programs against. If I recall, ES5 strict mode has gotten rid of all of them with the notable exception of mutable Date.prototype that provides a covert channel. SES is an example of script that does everything it can to protect the JS environment (including fixing or working around almost-comformant environments bugs!) ## Threats that can be protected against From everything I have said, one clear thing is that protecting the JavaScript is an opt-in. If you do not opt-in to a secure environment, you're left to be a prey by default. The list of potential attacks is probably endless. Adding an Object.prototype.get function and waiting for people to use Object.defineProperty is such an attack. Putting an accessor on Array.prototype[0] is also a possibility. # What does it mean for the language evolution? The first category needs to be taken care of and is. Next features are carefully thought out to avoid unprotectable threats. The second category is a bit more debatable. There is tension due to the fact that the vast majority of JS developers aren't aware that JavaScript security requires an opt-in like SES and as a consequence are victim of whatever buggy or malicious code they happen to add to their webpages. Given that security requires an opt-in anyway, is it worthwhile to modify the language (like Object.defineProperty) to protect for some cases but not others? I would tend to say no. Regarding Andrea's specific case, I'd like to mention that proxy handlers are also based on [[Get]]. The inheritance is actually used in some cases for trap reuse (it was even more the case in the previous design, but still is the case). Should inheritance be prevented here too and ruin a valid use case? Just because an attacker might add an Object.prototype.someTrap and the defender might have forgotten to protect against it? I don't think it's worth the cost in
Re: (Map|Set|WeakMap)#set() returns `this` ?
On 6 December 2012 05:05, Rick Waldron waldron.r...@gmail.com wrote: Again, I reject the notion that someone might screw up is a valid argument for this, or any, discussion. It's one thing to be aware of the potential for misuse, but entirely another to succumb to fear driven design. Fear driven design is pejorative. The argument really is about the ability to do local reasoning as much as possible, which is a *very* valid concern, especially when reading somebody else's code using somebody else's library. I agree with other voices in this thread that in general, returning 'this' rather is an anti pattern. You can get away with it if you limit it to very few well-known library functions, but I doubt that blessing such style in the std lib does help that cause. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Thu, Dec 6, 2012 at 1:25 AM, David Herman dher...@mozilla.com wrote: On Dec 5, 2012, at 7:16 PM, Kevin Smith khs4...@gmail.com wrote: 2) Do we need `export *;`? I don't see the point of exporting every declaration in the current module scope. If the programmer wants to export a bunch of stuff, the other forms make that sufficiently easy. Exporting everything encourages bad (de-modular) design. Again, reasonable point. I *strongly* disagree. There are two important use cases for `export *` -- exporting everything you've defined, for little convenience modules or other quick tasks, and for wrapper modules where you want to export everything you import from somewhere else. Not having it means that you have to write everything explicitly, but more than that means that you end up with annoying busy work when you forget, and have to go figure out where the missing import or export is. I don't see any benefit to leaving it out (unlike `import *`, which was genuinely complex), and I don't think we need to tell programmers what good design is. Sam ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Summaries with comments: 1) export ExportSpecifierSet (, ExportSpecifierSet)* ; Brendan pointed out that other binding forms allow lists (including the import form), so why not this one? I actually didn't realize that lists are allowed with import: ImportDeclaration ::= import ImportClause (, ImportClause)* ; Fair enough. 2) Do we need `export *;`? Sam pointed out two use cases: 1) Conveniently exporting everything from little convenience modules. I'm not really convinced by this. It's just so easy to export things by adding the export keyword. 2) Re-exporting a collection of imports from other sources. This is better, at least in the case where you want to import a well-defined set of bindings and then re-export those same bindings later. Without `export *;`, you'd have to keep those binding lists in sync. Sounds reasonable to me. 3) I'm just OK with as. Note that it inverts the position of the string and the binding: Claus and Matthew suggested using the no-curlies form instead: import ga from ga; Dave responded by pointing out that we don't want from to have overloaded semantics. I actually think this form has potential, because it further aligns import with the other binding forms: var a = x; var { b } = y; // Symmetry! import a from x; import { b } from y; 5) Dynamic exports via `export = ?` could make interop with existing module systems easier. But how does that work? Dave gave an outline. I'm liking this. What are the downsides, if any? 6) Adding .js as the default resolution strategy: Dave responded that a custom resolution hook would be required for resources that don't end in .js. While that certainly works for current loader libraries, can we really mandate a js extension for all module URLs, forever? Because this default will effectively mandate that. Imagine if such a mandate came from CSS. URLs are a backbone concept of the internet and we shouldn't go fiddling with it. Dave also responded: I'll wait till it's fleshed out more didn't last long, eh? ;-) Anyway, I don't really understand this argument but do you think there's much value to a philosophical debate on es-discuss? Well, I practice Olympian levels of patience with my four small children day in and day out, so you'll have to forgive me if I've got none left over for you, good sir. ; ) - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Thu, Dec 6, 2012 at 9:42 AM, Kevin Smith khs4...@gmail.com wrote: Dave responded by pointing out that we don't want from to have overloaded semantics. I actually think this form has potential, because it further aligns import with the other binding forms: var a = x; var { b } = y; // Symmetry! import a from x; import { b } from y; +1 This also matches what Yehuda and Domenic proposed a few weeks ago. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: On dropping @names
On 5 December 2012 19:19, Claus Reinke claus.rei...@talk21.com wrote: their operational generativity perhaps being a mismatch with their seemingly static meaning in certain syntactic forms, This appears to be ungrounded. See below. Personally, I also consider that a non-issue, but it was concern that was raised. Implicit scoping in a language with nested scopes has never been a good idea (even the implicit var/let scopes in JS are not its strongest point). Prolog got away with it because it had a flat program structure in the beginning, and even that fell down when integrating Prolog-like languages into functional one, or when adding local sets of answers. Indeed. (Although I don't think we have implicit let-scopes in JS.) There are few enough cases (scope to nearest enclosing block unless there is an intervening conditional or loop construct, If you mean something like if (bla) let x; then that is not actually legal. to nearest for loop body if it appears in the loop header, to the right in a comprehension) that the difference might not matter. I would have preferred if let had not been modeled after var so much, but that is another topic. It is as clean as it can get given JS. And you may be surprised to hear that there are some voices who actually would have preferred a _more_ var-like behaviour. So I'm not sure how your concerns are being addressed by merely replacing a declarative scoping construct by an explicitly imperative gensym construct? We have the gensym construct anyway, @-names were intended to be merely syntactic sugar on top of that. Yes, so my question was how removing the sugar while keeping the semantics is going to address the concerns voiced in the meeting notes. The concern was that the sugar has issues, not symbol semantics as such. Scope extrusion semantics actually is equivalent to an allocation semantics. The only difference is that the store is part of your term syntax instead of being a separate runtime environment, but it does not actually make it more declarative in any deeper technical sense. Name generation is still an impure effect, albeit a benign one. For me, as a fan of reduction semantics, having all of the semantics explainable in the term syntax is an advantage!-) While it is simple to map between the two approaches, the nu-binders are more declarative in terms of simpler program equivalences: for gensym, one needs to abstract over generated symbols and record sharing of symbols, effectively reintroducing what nu-binders model directly. The program equivalences are the same, up to annoying additional congruences you need to deal with for nu-binders, which complicate matters. Once you actually try to formalise semantic reasoning (think e.g. logical relations), it turns out that a representation with a separate store is significantly _easier_ to handle. Been there, done that. gensym is more imperative in terms of the simplest implementation: create a globally unused symbol. Which also happens to be the simplest way of implementing alpha-conversion. Seriously, the closer you look, the more it all boils down to the same thing. As Brendon mentions, nu-scoped variables aren't all that different from lambda-scoped variables. It's just that most implementations do not support computations under a lambda binder, so lambda variables do not appear to be dynamic constructs to most people, while nu binders rely on computations under the binders, so a static-only view is too limited. I think you are confusing something. All the classical name calculi like pi-calculus or nu-calculus don't reduce/extrude name binders under abstraction either. Not under lambda-binders, but under nu-binders - they have to. If was explaining that the static/dynamic differences that seem to make some meeting attendees uncomfortable are not specific to nu-scoped variables, but to implementation strategies. For lambda-binders, one can get far without reducing below them, but if one lifts that restriction, lambda-bound variables appear as runtime constructs, too, just as for nu-binders and nu-bound variables (gensym-ed names). Not sure what you're getting at precisely, but I don't think anybody would seriously claim that nu-binders are useful as an actual implementation strategy. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
+1 Compared to Node.js, I love ES6 exports, but Node.js module imports are easier to understand. Claus’ suggestion would make `import` similar to `let` and people could basically think of modules as objects. On Dec 6, 2012, at 10:41 , Claus Reinke claus.rei...@talk21.com wrote: Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. But that said, the convenience may well still trump the inconsistency. I think I'd prefer consistency here, as it also allows to get rid of import foo as foo; and replace it with import foo from foo; which keeps the order of import {x,y} from foo and it is all just module-level destructuring (fewer new concepts). -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: (Map|Set|WeakMap)#set() returns `this` ?
On Wed, Dec 5, 2012 at 8:05 PM, Rick Waldron waldron.r...@gmail.com wrote: On Wed, Dec 5, 2012 at 10:33 PM, Bill Frantz fra...@pwpconsult.com wrote: On 12/5/12 at 1:50 AM, jussi.kallioko...@gmail.com (Jussi Kalliokoski) wrote: I personally think returning `this` in absence of any meaningful value (and chaining in general) is a bad pattern. /lurk I have to agree with Jussi here. Whenever I consider chaining using the returned values from the various things called, my programming paranoia hair stands on end. Let me try to explain: Whenever I program, I try to trust as little code as possible. With chaining, there are two possibilities for getting the wrong answer in the returned value: * I or someone else wrote it, but screwed up, * Someone hostile wrote it and is trying to trip me up. If there is a language construct that allows chaining -- like the Pascal with construct -- then I am only trusting the language*, not other fragments of programs. If I depend on things I call returning the correct this, then I am depending on them and my dependency set is a lot larger. A larger dependency set makes me nervous. Cheers - Bill * For the really paranoid, minimizing the parts of the language depended on is important. Not all JS implementations behave the same way in the corner cases. Again, I reject the notion that someone might screw up is a valid argument for this, or any, discussion. It's one thing to be aware of the potential for misuse, but entirely another to succumb to fear driven design. Is fear driven design just a derogatory phrase for defensive programming? Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Module Comments
For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. In general, it tries to eliminate the ExportSpecifierSet and ImportSpecifierSet microsyntaxes in favor of standard object literal/destructuring forms, respectively. It also made export and import syntax symmetric. It apparently failed to get much traction among committee members, mainly because of objections to our reformation of the export-side syntax. (Second-hand info.) E.g. the current export function foo() { } was preferred to the proposed export { foo() { } }, and---less aesthetically---our special behavior for ObjectLiteral expressions over other expressions was a bit weird. I still think the import-side reformation is important and stand by everything in the proposal in that regard. As mentioned in other messages in this thread, the current form is confusingly dual-natured. And I maintain that the incomplete semi-destructuring microsyntax of ImportSpecifierSet adds a lot of cognitive burden. If we can start by fixing the import side, I have some other ideas on how to make the export side better that hopefully will be more appealing to the committee. But I don't want to try proposing those yet until we can get the buy-in on fixing import. From: es-discuss-boun...@mozilla.org [es-discuss-boun...@mozilla.org] on behalf of Erik Arvidsson [erik.arvids...@gmail.com] Sent: Thursday, December 06, 2012 09:54 To: Kevin Smith Cc: es-discuss Subject: Re: Module Comments On Thu, Dec 6, 2012 at 9:42 AM, Kevin Smith khs4...@gmail.commailto:khs4...@gmail.com wrote: Dave responded by pointing out that we don't want from to have overloaded semantics. I actually think this form has potential, because it further aligns import with the other binding forms: var a = x; var { b } = y; // Symmetry! import a from x; import { b } from y; +1 This also matches what Yehuda and Domenic proposed a few weeks ago. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 15:42, Kevin Smith khs4...@gmail.com wrote: 5) Dynamic exports via `export = ?` could make interop with existing module systems easier. But how does that work? Dave gave an outline. I'm liking this. What are the downsides, if any? The downside is that it introduces a severe anomaly into the module semantics (a module which actually has no instance). I could live with this feature if we were to find a way to explain it in terms of simple syntactic sugar on both the import and export side, but screwing and complicating the semantics for minor syntactic convenience is not something I am particularly fond of. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
One plausible variant to our proposal that might be easier to swallow (as it doesn't have the special-cased ObjectLiteral problem) is: - Replace `export ExportSpecifierSet` with `export ObjectLiteral` for static exports - Allow `export = foo` (or something like it) for single exports - Unify the import syntax to support the full destructuring syntax and to work on both static and single exports This retains the advantages of reducing micro-syntax and reforming import without forcing an awkward special-casing of `export ObjectLiteral` On Thu, Dec 6, 2012 at 7:44 AM, Domenic Denicola dome...@domenicdenicola.com wrote: For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. In general, it tries to eliminate the ExportSpecifierSet and ImportSpecifierSet microsyntaxes in favor of standard object literal/destructuring forms, respectively. It also made export and import syntax symmetric. It apparently failed to get much traction among committee members, mainly because of objections to our reformation of the export-side syntax. (Second-hand info.) E.g. the current export function foo() { } was preferred to the proposed export { foo() { } }, and---less aesthetically---our special behavior for ObjectLiteral expressions over other expressions was a bit weird. I still think the import-side reformation is important and stand by everything in the proposal in that regard. As mentioned in other messages in this thread, the current form is confusingly dual-natured. And I maintain that the incomplete semi-destructuring microsyntax of ImportSpecifierSet adds a lot of cognitive burden. If we can start by fixing the import side, I have some other ideas on how to make the export side better that hopefully will be more appealing to the committee. But I don't want to try proposing those yet until we can get the buy-in on fixing import. -- *From:* es-discuss-boun...@mozilla.org [es-discuss-boun...@mozilla.org] on behalf of Erik Arvidsson [erik.arvids...@gmail.com] *Sent:* Thursday, December 06, 2012 09:54 *To:* Kevin Smith *Cc:* es-discuss *Subject:* Re: Module Comments On Thu, Dec 6, 2012 at 9:42 AM, Kevin Smith khs4...@gmail.com wrote: Dave responded by pointing out that we don't want from to have overloaded semantics. I actually think this form has potential, because it further aligns import with the other binding forms: var a = x; var { b } = y; // Symmetry! import a from x; import { b } from y; +1 This also matches what Yehuda and Domenic proposed a few weeks ago. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Yehuda Katz (ph) 718.877.1325 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: On dropping @names
I would have preferred if let had not been modeled after var so much, but that is another topic. It is as clean as it can get given JS. I was hoping for something roughly like let lhs = rhs; statements // non-recursive, scope is statements let { declarations }; statements // recursive, scope is declarations and statements No hoisting needed to support recursion, no temporal deadzones, no problem with referring to old x when defining x non-recursively. And less mixing of declarations and statements. And you may be surprised to hear that there are some voices who actually would have preferred a _more_ var-like behaviour. Well, in the beginning let was meant to replace var, so it had to be more or less like it for an easy transition. Later, even that transition was considered too hard, so var an let coexist, giving more freedom for let design. At least, that is my impression. The program equivalences are the same, up to annoying additional congruences you need to deal with for nu-binders, which complicate matters. Once you actually try to formalise semantic reasoning (think e.g. logical relations), it turns out that a representation with a separate store is significantly _easier_ to handle. Been there, done that. Hmm, I used to find reasoning at term level quite useful (a very long time ago, I was working on a functional logic language, which had something like nu-binders for logic variables). Perhaps it depends on whether one reasons about concrete programs (program development) or classes of programs (language-level proofs). gensym is more imperative in terms of the simplest implementation: create a globally unused symbol. Which also happens to be the simplest way of implementing alpha-conversion. Seriously, the closer you look, the more it all boils down to the same thing. Yep. Which is why I thought to speak up when I saw those concerns in the meeting notes;-) Not under lambda-binders, but under nu-binders - they have to. If was explaining that the static/dynamic differences that seem to make some meeting attendees uncomfortable are not specific to nu-scoped variables, but to implementation strategies. For lambda-binders, one can get far without reducing below them, but if one lifts that restriction, lambda-bound variables appear as runtime constructs, too, just as for nu-binders and nu-bound variables (gensym-ed names). Not sure what you're getting at precisely, but I don't think anybody would seriously claim that nu-binders are useful as an actual implementation strategy. More as a user-level representation of whatever implementation strategy is used behind the scenes, just as lambda-binders are a user-level representation of efficient implementations. But to clarify the point: Consider something like: (\x. (\y. [y, y]) x) Most implementations won't reduce under the \x., nor will they bother to produce any detailed result, other than 'function'. So those x and y are purely static constructs. However, an implementation that does reduce under the \x. will need to deal with x as a dynamic construct, passing it to \y. to deliver the result (\x. [x,x]). Now, the same happens with nu-binders, or private names: after bringing them in scope, computation continues under the nu-binder, so there is a dynamic representation (the generated symbol) of the variable. My point is that there isn't anything worrying about variables appearing at dynamic constructs, nor is it specific to private names - normal variables appearing to be static is just a consequence of limited implementations. What is static is the binding/scope structure, not the variables. Since we mostly agree, I'll leave this here. Perhaps it helps the meeting participants with their concerns. Claus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 16:44, Domenic Denicola dome...@domenicdenicola.com wrote: For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. I strongly agree with having the import x from ... import {x, y} from ... symmetry and consistent binding on the left. However, the more radical parts of your proposal (allowing arbitrary export expressions, and arbitrary import patterns) do not work. The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Consider: module A { let o = { x: [1, 2], f() { o.x = 666 } } export o } import {x: [a, b], f} from A a = 3 // is this supposed to modify the array? f() print(a) // x is no longer an array, a doesn't even exist In other words, what you are proposing has no longer anything to do with static scoping. You could arguably make this saner by interpreting nested patterns in an import as copying, not aliasing, but I think mixing meanings like that would be rather confusing and surprising. You could also consider imports always meaning copying, but then you exporting a variable will no longer be useful. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
The downside is that it introduces a severe anomaly into the module semantics (a module which actually has no instance). I could live with this feature if we were to find a way to explain it in terms of simple syntactic sugar on both the import and export side, but screwing and complicating the semantics for minor syntactic convenience is not something I am particularly fond of. What if this: export = boo; Actually creates a static export with some exotic name, say __DEFAULT__ (for the sake of argument) and initializes it to the value boo. And this form: import boo from boo.js; Creates a binding to __DEFAULT__ in boo.js, if it exists, or to the module instance of boo.js otherwise. Would that work as a desugaring? - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: On dropping @names
On 6 December 2012 17:25, Claus Reinke claus.rei...@talk21.com wrote: I was hoping for something roughly like let lhs = rhs; statements // non-recursive, scope is statements let { declarations }; statements// recursive, scope is declarations and statements Problem is that you need mutual recursion between different binding forms, not just 'let' itself. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 17:33, Kevin Smith khs4...@gmail.com wrote: The downside is that it introduces a severe anomaly into the module semantics (a module which actually has no instance). I could live with this feature if we were to find a way to explain it in terms of simple syntactic sugar on both the import and export side, but screwing and complicating the semantics for minor syntactic convenience is not something I am particularly fond of. What if this: export = boo; Actually creates a static export with some exotic name, say __DEFAULT__ (for the sake of argument) and initializes it to the value boo. And this form: import boo from boo.js; Creates a binding to __DEFAULT__ in boo.js, if it exists, or to the module instance of boo.js otherwise. Would that work as a desugaring? I suggested something along these lines at some point in the past, but there were some concerns with it that, unfortunately, I do not remember. Maybe it can be resolved. Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
What about trying it the other way, flip everything. import foo as bar; import foo as { baz } On Thu, Dec 6, 2012 at 8:42 AM, Andreas Rossberg rossb...@google.comwrote: On 6 December 2012 17:33, Kevin Smith khs4...@gmail.com wrote: The downside is that it introduces a severe anomaly into the module semantics (a module which actually has no instance). I could live with this feature if we were to find a way to explain it in terms of simple syntactic sugar on both the import and export side, but screwing and complicating the semantics for minor syntactic convenience is not something I am particularly fond of. What if this: export = boo; Actually creates a static export with some exotic name, say __DEFAULT__ (for the sake of argument) and initializes it to the value boo. And this form: import boo from boo.js; Creates a binding to __DEFAULT__ in boo.js, if it exists, or to the module instance of boo.js otherwise. Would that work as a desugaring? I suggested something along these lines at some point in the past, but there were some concerns with it that, unfortunately, I do not remember. Maybe it can be resolved. Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- - Matthew Robb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 17:46, Matthew Robb matthewwr...@gmail.com wrote: What about trying it the other way, flip everything. import foo as bar; import foo as { baz } Hm, I don't understand. What would that solve? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Well the argument being that as it stands it's inconsistent having the identifier on the RHS for import from and LHS in import as: import baz from foo; import foo as foo; I'm just throwing out simple options for solving that inconsistency. Possibly even thinking about them as declarations makes the simplest sense anyway: var foo = import foo; var { baz } = import foo; On Thu, Dec 6, 2012 at 8:49 AM, Andreas Rossberg rossb...@google.comwrote: On 6 December 2012 17:46, Matthew Robb matthewwr...@gmail.com wrote: What about trying it the other way, flip everything. import foo as bar; import foo as { baz } Hm, I don't understand. What would that solve? /Andreas -- - Matthew Robb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. Could we eliminate the hack on the export side instead? Every module instance has a $DEFAULT export binding. Normally, it is set to the module instance itself. `export = ?` overrides the value of that binding. `import x from y` binds $DEFAULT in y to x. Maybe? - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: (Map|Set|WeakMap)#set() returns `this` ?
On Thu, Dec 6, 2012 at 3:48 AM, Jussi Kalliokoski jussi.kallioko...@gmail.com wrote: And if it comes down to precedents in the language, even Array#forEach() returns undefined, contrary to popular libraries out there. Let's keep some consistency here. Array.prototype.map and Array.prototype.filter return newly created arrays and as such, are chainable (and will have the same benefits as I described above) // map and return a fresh iterable of values array.map( v = ... ).values() // map and return a fresh iterable of entries (index/value pairs) array.filter( v = ... ).entries() I agree with you, fear-driven design is bad. But don't you agree that if there's chaining, it's better done at language level rather than having all APIs be polluted by `this` returns? Who said all APIs would return `this`? We specified a clear criteria. After all, the APIs can't guarantee a `this` return, Yes they can, they return what the specification defines them to return. since they might have something actually meaningful to return, otherwise we might as well just replace `undefined` with `this` as the default return value. In the cases I presented, I believe that returning `this` IS the meaningful return. We could introduce mutable primitives so that meaningful return values could be stored in arguments, kinda like in C, but instead of error values, we'd be returning `this`, heheheh. :) I'm curious, do you have any code examples of maps/sets that could be made clearer by chaining? This is incredibly frustrating and indicates to me that you're not actually reading this thread, but still find it acceptable to contribute to the discussion. https://gist.github.com/4219024 Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: (Map|Set|WeakMap)#set() returns `this` ?
On Thu, Dec 6, 2012 at 6:53 AM, Andreas Rossberg rossb...@google.comwrote: On 6 December 2012 05:05, Rick Waldron waldron.r...@gmail.com wrote: Again, I reject the notion that someone might screw up is a valid argument for this, or any, discussion. It's one thing to be aware of the potential for misuse, but entirely another to succumb to fear driven design. Fear driven design is pejorative. I'll own that, my apologies. The argument really is about the ability to do local reasoning as much as possible, which is a *very* valid concern, especially when reading somebody else's code using somebody else's library. I agree with other voices in this thread that in general, returning 'this' rather is an anti pattern. The evidence I've brought to this discussion shows that the most widely used and depended upon libraries heavily favor the pattern. You can get away with it if you limit it to very few well-known library functions, We established a criteria for built-ins, I don't think we should be using return this by default, but indeed we should where it will be an expressive benefit. https://gist.github.com/4219024 but I doubt that blessing such style in the std lib does help that cause. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: (Map|Set|WeakMap)#set() returns `this` ?
On Thu, Dec 6, 2012 at 10:34 AM, Mark S. Miller erig...@google.com wrote: Is fear driven design just a derogatory phrase for defensive programming? Not at all. I wrote fear driven design in a moment of frustration, referring only to the opposition of adopting a (widely held as) best practice based solely on what appears to be subjective opinions versus objective observation of real world use cases. The argument: if you have to scan the code to another page to figure out which object the code is interacting with, it's bad readability Would apply in only one extreme case that is so incredibly stupid, I posit this will be an anomaly: set.add(...).add(...).add(...).add(...).add(...).add(...).add(...)... The likely very common cases are quite nice and not at all confusing to read: (copied from an earlier message in this thread) Add value to the Set and get a fresh iterable for the keys, values, entries: set.add( value ).keys(); set.add( value ).values(); set.add( value ).entries(); Add value to the Set and send each value in the set to another operation: set.add( value ).forEach( item = ...send to some operation ); Add value to the Set and spread into an array of unique items: [ ...set.add(value) ]; // [ a, b, c, ... ] And of course, the same for Map. More here: https://gist.github.com/4219024 I have respect for valid technical and security related concerns and would certainly love to discuss those if any have been identified. Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: (Map|Set|WeakMap)#set() returns `this` ?
On Thu, Dec 6, 2012 at 8:25 PM, Jussi Kalliokoski jussi.kallioko...@gmail.com wrote: On Thu, Dec 6, 2012 at 7:32 PM, Rick Waldron waldron.r...@gmail.comwrote: Array.prototype.map and Array.prototype.filter return newly created arrays and as such, are chainable (and will have the same benefits as I described above) // map and return a fresh iterable of values array.map( v = ... ).values() // map and return a fresh iterable of entries (index/value pairs) array.filter( v = ... ).entries() Of course, but that's pears and apples, .set() doesn't create a new instance. And btw, that .values() is redundant. Wait, sorry about that, wrote before I investigated. I agree with you, fear-driven design is bad. But don't you agree that if there's chaining, it's better done at language level rather than having all APIs be polluted by `this` returns? Who said all APIs would return `this`? We specified a clear criteria. You're dodging my question: isn't it better for the chaining to be supported by the language semantics rather than be injected to APIs in order to have support? After all, the APIs can't guarantee a `this` return, Yes they can, they return what the specification defines them to return. What I mean is that the not all functions in an API can return `this` anyway (like getters), so it's inconsistent. After all, it's not a very useful API if you can just set but not get. since they might have something actually meaningful to return, otherwise we might as well just replace `undefined` with `this` as the default return value. In the cases I presented, I believe that returning `this` IS the meaningful return. No, it's a generic return value if it's applied to everything that's not a getter. We could introduce mutable primitives so that meaningful return values could be stored in arguments, kinda like in C, but instead of error values, we'd be returning `this`, heheheh. :) I'm curious, do you have any code examples of maps/sets that could be made clearer by chaining? This is incredibly frustrating and indicates to me that you're not actually reading this thread, but still find it acceptable to contribute to the discussion. https://gist.github.com/4219024 I'm sorry you feel that way, but calm down. I've read the gist all right and just read the latest version, and imho it's quite a biased example, you're making it seem harder than it actually is. For example, the last paragraph: ( map.set(key, value), set ).keys(); // simpler: map.set(key, value); map.keys(); ( set.add(value), set ).values(); // simpler: set.add(value); set.values; ( set.add(value), set ).forEach( val = ); // simpler: set.add(value); set.forEach( val = ); Why would you need to stuff everything in one line? This way it's more version control friendly as well, since those two lines of code have actually nothing to do with each other, aside from sharing dealing with the same object. Why do you want to get all of those things from .set()/.add(), methods which have nothing to do with what you're getting at? Cheers, Jussi ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Every module instance has a $DEFAULT export binding. Normally, it is set to the module instance itself. `export = ?` overrides the value of that binding. `import x from y` binds $DEFAULT in y to x. Maybe? That would be how Node.js does. For those unfamiliar with how it works, it's basically like this var mod = { exports: {} }; (function(module, exports){ ... })(mod, mod.exports); So if you assign things to the default exports like exports.firstExport = value; exports.secondExport = value; You're assigning to the default provided export object. But since you also have access to the container (module) you can opt to fully overwrite it module.exports = singleExportedThing; If you added things to exports and then overwrote module.exports with a new value, those initial exports will not be visible as exports because the original export object is overwritten. exports.willBeOverwritten = true; module.exports = singleExportedThing; So the single export route is opt-in, but it's opted into in the large majority of cases. On Thu, Dec 6, 2012 at 11:54 AM, Kevin Smith khs4...@gmail.com wrote: Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. Could we eliminate the hack on the export side instead? Every module instance has a $DEFAULT export binding. Normally, it is set to the module instance itself. `export = ?` overrides the value of that binding. `import x from y` binds $DEFAULT in y to x. Maybe? - Kevin ___ 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: Module Comments
David Herman wrote: Cool, definitely want the plain identifier form, it's part of the binding (and destructuring) pattern language. Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. You are so right. Therefore I think Yehuda et al. (as Andreas affirmed) are spot-on in advocating import foo from foo; // import the singleton export = thing from foo import {bar} from foo; // import the bar export from foo and we don't have a RTL problem. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Comments on Meeting Notes
Luke Hoban lu...@microsoft.com wrote: IE10 sort of did. The following code: (function(){ 'use strict'; return !this; })(); returns false in IE10. Who knows what other deviations from the standard there are... That code returns true in IE10 standards mode. See test262.ecmascript.orgfor tests validating this and other ES5 implementation compatibility. If you see things not covered there, open bugs suggesting new tests: https://bugs.ecmascript.org/enter_bug.cgi?product=Test262. Indeed, it must have been an earlier IE10 preview version then. I apologize for the accusation. -- Michał Z. Gołębiowski ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: (Map|Set|WeakMap)#set() returns `this` ?
On Thu, Dec 6, 2012 at 8:44 PM, Rick Waldron waldron.r...@gmail.com wrote: values() returns an iterable of the values in the array. Array, Map and Set will receive all three: keys(), values(), entries(). Feel free to start a new thread if you want to argue about iterator protocol. Yes, I apologized for that mistake already, I remembered incorrectly. I don't have a want to argue, just like I'm sure you don't. I'm absolutely not dodging the question, I answered this in a previous message, much earlier. Cascade/monocle/mustache is not a replacement here. That wasn't the question I asked. Cascade/monocle/mustache aren't even ready yet, and are hence in no way an indication that chaining cannot be made a language-side construct. I believe it can and will, and at that point, returning this becomes completely meaningless. But (I don't see) how can you fix this on the language syntax side: var obj = { foo: bar, baz: taz } set.add(obj) return set instead of simply: return set.add({ foo: bar, baz: taz }) What I mean is that the not all functions in an API can return `this` anyway (like getters), so it's inconsistent. After all, it's not a very useful API if you can just set but not get. That's exactly my point. The set/add API return this, allowing post-mutation operations to be called: such as get or any of the examples I've given throughout this thread. What? I'm really sorry, but I can't understand how what I said leads to your point. But I bet we're both wasting our time with this part, so it's probably best to just leave it. No one said anything about applying return this to everything that's not a getter. That was exactly what the criteria we have consensus on defines. It's in the meeting notes for Nov. 29. Sorry, about that, the meeting notes (in the part Cascading this returns) just say: Supporting agreement (Discussion to determine a criteria for making this API specification distinction) Consensus... with the criteria that these methods are not simply a set of uncoordinated side effects that happen to have a receiver in common, but a set of coordinated side effects on a specific receiver and providing access to the target object post-mutation. With no reference to the logic behind the conclusion (these methods are not simply a set of uncoordinated side effects that happen to have a receiver in common). I fail to see how .set()/.add() are a special case. Am I missing something? Please read everything I've written so far, it's not fair to make me constantly repeat myself in this thread. I agree, and I'm sorry, but I have, at least everything on this thread, those referred to and those that have seemed related. I'm doing my best, but I'm afraid I can't keep up with every thread in my inbox, and I don't think it's a good reason for me not to contribute at all. Of course I could've shown it as you have here, but I made examples where the intention was to match the preceding examples illustrated in the gist. Fair enough, but I fail to see the convenience in your examples. Why would you need to stuff everything in one line? As evidenced several times throughout this thread, the pattern is widely implemented in the most commonly used library APIs, so I guess the answer is The kids love it. document.write() is widely implemented too, doesn't make it good or worth repeating. This way it's more version control friendly as well, since those two lines of code have actually nothing to do with each other, aside from sharing dealing with the same object. Why do you want to get all of those things from .set()/.add(), methods which have nothing to do with what you're getting at? You could just as easily have them on separate lines, but in cases where it might be desirable to immediately operate on the result of the mutation, chaining the next method call has the net appearance of a single tasks (if that's how a programmer so chooses to express their program). So it's taste, rather than convenience? Cheers, Jussi ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: (Map|Set|WeakMap)#set() returns `this` ?
On Thu, Dec 6, 2012 at 2:41 PM, Jussi Kalliokoski jussi.kallioko...@gmail.com wrote: On Thu, Dec 6, 2012 at 8:44 PM, Rick Waldron waldron.r...@gmail.comwrote: values() returns an iterable of the values in the array. Array, Map and Set will receive all three: keys(), values(), entries(). Feel free to start a new thread if you want to argue about iterator protocol. Yes, I apologized for that mistake already, I remembered incorrectly. I don't have a want to argue, just like I'm sure you don't. All this misses your important pears and oranges point. These are not mutable APIs, which is a key distinction. The sort method would have been a good example of a mutable API returning `this`. But it's not exactly a model to emulate. I'm absolutely not dodging the question, I answered this in a previous message, much earlier. Cascade/monocle/mustache is not a replacement here. That wasn't the question I asked. Cascade/monocle/mustache aren't even ready yet, and are hence in no way an indication that chaining cannot be made a language-side construct. I believe it can and will, and at that point, returning this becomes completely meaningless. But (I don't see) how can you fix this on the language syntax side: var obj = { foo: bar, baz: taz } set.add(obj) return set instead of simply: return set.add({ foo: bar, baz: taz }) What I mean is that the not all functions in an API can return `this` anyway (like getters), so it's inconsistent. After all, it's not a very useful API if you can just set but not get. That's exactly my point. The set/add API return this, allowing post-mutation operations to be called: such as get or any of the examples I've given throughout this thread. What? I'm really sorry, but I can't understand how what I said leads to your point. But I bet we're both wasting our time with this part, so it's probably best to just leave it. No one said anything about applying return this to everything that's not a getter. That was exactly what the criteria we have consensus on defines. It's in the meeting notes for Nov. 29. Sorry, about that, the meeting notes (in the part Cascading this returns) just say: Supporting agreement (Discussion to determine a criteria for making this API specification distinction) Consensus... with the criteria that these methods are not simply a set of uncoordinated side effects that happen to have a receiver in common, but a set of coordinated side effects on a specific receiver and providing access to the target object post-mutation. With no reference to the logic behind the conclusion (these methods are not simply a set of uncoordinated side effects that happen to have a receiver in common). I fail to see how .set()/.add() are a special case. Am I missing something? Please read everything I've written so far, it's not fair to make me constantly repeat myself in this thread. I agree, and I'm sorry, but I have, at least everything on this thread, those referred to and those that have seemed related. I'm doing my best, but I'm afraid I can't keep up with every thread in my inbox, and I don't think it's a good reason for me not to contribute at all. Of course I could've shown it as you have here, but I made examples where the intention was to match the preceding examples illustrated in the gist. Fair enough, but I fail to see the convenience in your examples. Why would you need to stuff everything in one line? As evidenced several times throughout this thread, the pattern is widely implemented in the most commonly used library APIs, so I guess the answer is The kids love it. But which kids? There certainly appears to be quite a sampling bias in your survey -- I didn't see a single actual *collection* library. Sampling their choices would be the most helpful, not *what the kids are doing*. Plus there are other alternatives I haven't seen discussed, so the design space has barely been explored. For instance buckets [1] is a nice example of a collection library that takes an approach more reminiscent of javascript's existing array mutation methods -- its add method returns `true` if the item was newly created or `false` if it was already present in the collection -- a lot like javascript's delete operator. I'm not necessarily advocating for this, just offering up the idea that any survey should look closer at existing collection libraries to get a better feel for the full design space. [1] https://github.com/mauriciosantos/buckets document.write() is widely implemented too, doesn't make it good or worth repeating. That's a low blow :) This way it's more version control friendly as well, since those two lines of code have actually nothing to do with each other, aside from sharing dealing with the same object. Why do you want to get all of those things from .set()/.add(), methods which have nothing to do with what you're getting at? You could just as easily
Re: (Map|Set|WeakMap)#set() returns `this` ?
Had same thoughts on returning true or false as map.delete(key) would do. However, it's easy to have ambiguity there ... assuming the key can always be set, 'cause even a frozen Map should be able, and it is, to set a key internally, will true mean that key was not there ? will false mean that key was already set or we reached maximum number of keys? Shouldn't latter case be an error as it is for Array(Math.pow(2, 32) - 1).push(invalid array length); ? This boolean return is semantic with what delete does, less semantic with (setting[property] = value) logic thought but surely a valid possibility. Anyway, I would like to know what other TC39 members think, cause they all agreed already and i see this thread too dead and philosophical at this point ... :-/ We all have made our points but it has been decided then ... well, we should simply deal with it? br On Thu, Dec 6, 2012 at 12:14 PM, Dean Landolt d...@deanlandolt.com wrote: On Thu, Dec 6, 2012 at 2:41 PM, Jussi Kalliokoski jussi.kallioko...@gmail.com wrote: On Thu, Dec 6, 2012 at 8:44 PM, Rick Waldron waldron.r...@gmail.comwrote: values() returns an iterable of the values in the array. Array, Map and Set will receive all three: keys(), values(), entries(). Feel free to start a new thread if you want to argue about iterator protocol. Yes, I apologized for that mistake already, I remembered incorrectly. I don't have a want to argue, just like I'm sure you don't. All this misses your important pears and oranges point. These are not mutable APIs, which is a key distinction. The sort method would have been a good example of a mutable API returning `this`. But it's not exactly a model to emulate. I'm absolutely not dodging the question, I answered this in a previous message, much earlier. Cascade/monocle/mustache is not a replacement here. That wasn't the question I asked. Cascade/monocle/mustache aren't even ready yet, and are hence in no way an indication that chaining cannot be made a language-side construct. I believe it can and will, and at that point, returning this becomes completely meaningless. But (I don't see) how can you fix this on the language syntax side: var obj = { foo: bar, baz: taz } set.add(obj) return set instead of simply: return set.add({ foo: bar, baz: taz }) What I mean is that the not all functions in an API can return `this` anyway (like getters), so it's inconsistent. After all, it's not a very useful API if you can just set but not get. That's exactly my point. The set/add API return this, allowing post-mutation operations to be called: such as get or any of the examples I've given throughout this thread. What? I'm really sorry, but I can't understand how what I said leads to your point. But I bet we're both wasting our time with this part, so it's probably best to just leave it. No one said anything about applying return this to everything that's not a getter. That was exactly what the criteria we have consensus on defines. It's in the meeting notes for Nov. 29. Sorry, about that, the meeting notes (in the part Cascading this returns) just say: Supporting agreement (Discussion to determine a criteria for making this API specification distinction) Consensus... with the criteria that these methods are not simply a set of uncoordinated side effects that happen to have a receiver in common, but a set of coordinated side effects on a specific receiver and providing access to the target object post-mutation. With no reference to the logic behind the conclusion (these methods are not simply a set of uncoordinated side effects that happen to have a receiver in common). I fail to see how .set()/.add() are a special case. Am I missing something? Please read everything I've written so far, it's not fair to make me constantly repeat myself in this thread. I agree, and I'm sorry, but I have, at least everything on this thread, those referred to and those that have seemed related. I'm doing my best, but I'm afraid I can't keep up with every thread in my inbox, and I don't think it's a good reason for me not to contribute at all. Of course I could've shown it as you have here, but I made examples where the intention was to match the preceding examples illustrated in the gist. Fair enough, but I fail to see the convenience in your examples. Why would you need to stuff everything in one line? As evidenced several times throughout this thread, the pattern is widely implemented in the most commonly used library APIs, so I guess the answer is The kids love it. But which kids? There certainly appears to be quite a sampling bias in your survey -- I didn't see a single actual *collection* library. Sampling their choices would be the most helpful, not *what the kids are doing*. Plus there are other alternatives I haven't seen discussed, so the design space has barely been explored. For instance buckets [1] is a
Re: On dropping @names
I was hoping for something roughly like let lhs = rhs; statements // non-recursive, scope is statements let { declarations }; statements// recursive, scope is declarations and statements Problem is that you need mutual recursion between different binding forms, not just 'let' itself. Leaving legacy var/function out of it, is there a problem with allowing mutually recursive new declaration forms in there? let { // group of mutually recursive bindings [x,y] = [42,Math.PI]; // initialization, not assignment even(n) { .. odd(n-1) .. } // using short method form odd(n) { .. even(n-1) .. } // for non-hoisting functions class X { .. } class C extends S { .. new X( odd(x) ) .. } class S { } }; if (even(2)) console.log( new C() ); Or did I misunderstand your objection? Claus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: (Map|Set|WeakMap)#set() returns `this` ?
Andrea Giammarchi wrote: Anyway, I would like to know what other TC39 members think, cause they all agreed already You've heard from Mark and me (also Jason Orendorff of Mozilla, who is de-facto champion of some ES6 proposals) in this thread, along with Rick. You won't get a definitive resolution on es-discuss from TC39, however. Allen may have a thought on how to proceed, but I think this discussion is still valuable so long as we don't rehash or butt heads too much. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Comments on Meeting Notes
On 12/04/2012 03:57 PM, Brendan Eich wrote: Allen Wirfs-Brock wrote: The timing of copying is only an issue if the function actually assigns to a formal parameter. Such assignments should be pretty easy to (conservatively) statically check for. I'm telling you what engines do. Not what they might do. I did assignment analysis in SpiderMonkey for Firefox 3.6, it was helpful in its day. I think a bunch has been ripped out because modern JITs don't need it. [...]the point I made, cited above: engines don't do it currently and feel little pressure to do so. Chicken and egg. SpiderMonkey's implementation of the arguments object functions exactly as described here for functions with strict mode code -- actually for all functions, I think. Regarding the strict mode semantics specifically, it was fairly easy to make those optimizations when I was implementing the various strict mode arguments semantics, so I did them. There hasn't been a time where SpiderMonkey's had strict mode arguments semantics, without these optimizations. Jeff ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss