Re: importModule followup
On Aug 18, 2008, at 8:35 AM, Brendan Eich wrote: Scripts are synchronously loaded today, but browsers are working on async loading techniques, and IE promulgated the defer attribute into HTML5. Er, into HTML4. (Coffee time! ;-) /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Picking property by attribute
On Aug 18, 2008, at 9:28 AM, Yuh-Ruey Chen wrote: OK, with the advent of ES-Harmony, I have no clue whether the language will support iterators (and maybe generators) We talked about these in Oslo. My notes say generators received favorable comments, with the thought from Mark Miller that the introductory keyword might better be 'generator' than 'function'. These were never a bone of contention between factions, AFAIK. or catch-all methods. These required the meta namespace in ES4 as proposed. I know that namespaces are out. Then you do have a clue about catchalls as proposed :-/. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
On Aug 18, 2008, at 4:55 PM, David-Sarah Hopwood wrote: I really like the general approach and the simplicity of Ihab's proposal. Also I strongly agree that a module should *not* implicitly capture the lexical scope in which it is imported. I don't think anyone proposed any such thing. Do you? I'm not sure why 'provide' needs new syntax, though. Syntax is (a) often good UI; (b) special form expression where there's no library way to say what the special form says. Why should everything be lambda-coded? What if I change your bindings for module and provide? (Maybe I can't; please explain why not.) I'm not being snarky (or not merely ;-). The pre-Harmony extreme of no new syntax, ever is dead. Asking whether new syntax pays for itself is ok, but the question becomes vacuous when the only demonstration against new syntax begs questions about usability and integrity. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: local
On Aug 21, 2008, at 6:54 PM, Mark S. Miller wrote: On Thu, Aug 21, 2008 at 3:07 PM, Brendan Eich [EMAIL PROTECTED] wrote: [...] A strict mode or similar [...]. The greater its distance from the standard mode, A nit: Please let's start referring to the opposite of strict mode as non-strict mode. Once these become official, they will both be standard. Ok! /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Aug 21, 2008, at 7:26 PM, Peter Michaux wrote: It works in practice as context of syntax sometime matters. Context matters in many ways in JS and other languages. This is definitely an example of the same syntax having semantically different meaning (actually opposite meanings) The syntax is not the same because of the left-hand side of assignment (=) vs. right. Mutation in JS is a concern; you have to know whether you're assigning or using a variable; you have to pay attention to context. which was an objection to the use of return in an let statement if a let statement desugars to a function-expression call. I anticipated this when I wrote in an earlier reply: Different semantics should have distinct syntax; similarity or symmetry may motivate reuse of syntactic forms or ideas. Here, there is no function to return y from, to be assigned to z. You could say let desugars, but it doesn't say what it means. You are proposing the *same* semantics for different syntax (let vs. function expression that's called right away). Destructuring patterns use the same (or similar, in the case of the object shorthand) syntax for related (complementary, symmetric about =) semantics. See the difference? That 'return' is the common syntax inside your let-as-lambda-call is not the source of similarity, since the outer syntax (let vs. function) is dissimilar. The cognitive load comes from the question: where does return go?, since it is a control flow break. The Smalltalk page I linked to earlier talks about this. Another example in favor of similar syntax for similar or related use- cases: JS uses function forms in expressions and definitions. The contexts and effects differ, but the similarity motivates syntax re-use. Not so the case with the same (not similar, same -- desugaring) semantics for your different outer syntaxes, especially when the cost is loss of pellucid return, break, continue, plus the bigger loss of purely lexical scope, which by contrast let in JS1.7 provides. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: local
On Aug 21, 2008, at 10:10 PM, Breton Slivka wrote: In the case of let statements, as I understand it, the current proposal, and how let works in firefox is that let (x = 2, y = x) { print(y); } desugars to { let x = 2, y = x; print(y); } No, because in the latter, as for var in a program or function body, let x is hoisted to the top of the block, so y's initializer x is not the value of the outer x, but the undefined initial value of the hoisted inner x. So let statements really are different from let declarations in blocks. New let forms may look spooky or useful, depending on your language background. Schemers tend not to be spooked; folks who started with JS, Java, C++ or C may bolt ;-). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Attribute defaults for Object.defineProperty
On Aug 22, 2008, at 11:53 AM, David-Sarah Hopwood wrote: Allen Wirfs-Brock wrote: Michael Haufe [mailto:[EMAIL PROTECTED] said: Although I'd prefer to control Deletable separately from Fixed, Using a single state to control deletability, attribute mutability, and property transformation/replacement is a compromise. There may be some situations where somebody would really like to control these separately but it is probably a pretty limited use case. If you can set attribute mutability, then you can set the Delete attribute. If you can set the Delete attribute, then you can delete the property (and its current attributes). If you can delete the property, then you can recreate it with different attributes. So, there is neither a security nor an expressiveness argument for making any distinction between these rights. An argument for separating them would have to be based on convenience (but it seems less convenient, not more), or on preventing inadvertent, non-malicious changes, or possibly on efficiency (but these operations are probably not common enough for that to be significant). Agreed on all points. The prototype-based language Wheat started with what looked like Unix owner/group/other permission bits, but the nonsense or dangerous combinations were eliminated (if my memory serves). We should not even flirt with this kind of false orthogonality. That's why DontDelete was not a bad name in its day. Even in ES1 or the prior JavaScript and JScript implementations had something like it (SpiderMonkey's name is permanent). It's not that configurable is bad, even if overlong. It is less concrete in terms of what is controlled and why. Concrete names are generally better. No CanMod, though -- I was flashing back to 6BIT charsets on DEC 36- bit processors ;-). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Aug 23, 2008, at 8:44 AM, [EMAIL PROTECTED] wrote: On Sat, Aug 23, 2008 at 1:49 AM, Mike Cowlishaw [EMAIL PROTECTED] wrote: Finally, I'd like to take a poll: Other than people working on decimal at IBM and people on the EcmaScript committee, is there anyone on this list who thinks that decimal adds significant value to EcmaScript? If so, please speak up. Thanks. Decimal arithmetic is sufficiently important that it is already available in all the 'Really Important' languages except ES (including C, Java, Python, C#, COBOL, and many more). EcmaScript is the 'odd one out' here, and not having decimal support makes it terribly difficult to move commercial calculations to the browser for 'cloud computing' and the like. Decimals in Java are implemented at the library level, as java.math.BigDecimal. There is no expectation that intrinsic math operators work on them. Is this approach valid for ES; if not, then why not? See http://jroller.com/cpurdy/entry/the_seven_habits_of_highly1 (especially the first comment, by Bob McWhirter) also see https://bugzilla.mozilla.org/show_bug.cgi?id=5856 All linked from the still-useful http://wiki.ecmascript.org/doku.php?id=discussion:decimal Implementing decimals at the library level has the advantage that they can be deployed today, as functional (if slower) ES code, and optimized later on by a native implementation with no loss of compatibility. http://gwt-math.googlecode.com/svn/trunk/gwt-math/src/main/resources/ com/googlecode/gwt/math/public/js/bigdecimal.js ;-) After all, it will be several years before the next ES version becomes reliably available on consumers' browsers. Several years or less than a year from final spec, depending on the vendor's commitments to standards. Does this manner of easing migration inform the approach being taken? Not really. If you want GWT, use it. If you want a library, they are out there. The problem is making a new type in ES3.1's spec work, both now and in the future when operators are added (so we can avoid the laughable but totally predictable outcome Bob McWhirter cited in Purdy's blog). Conversely, if one is to add support for the intrinsic math operators on decimals, does the required work generalize easily to arithmetic on complex numbers and matrices? We might hope to know by looking at other languages, but really, doing the work in the context of backward JS compatibility is required. So again, doing what Sam is doing in developing patches against open source JS implementations seems at least as valuable as trying to spec Decimal quickly, making it law, and then hoping it works out in the future *and* somehow leads to a taller numeric tower. Will the addition of complex numbers and matrices require more difficult work about how they interoperate with existing number representations (including, at that point, decimal numbers)? How, if at all, does this inform the present discussion? You might find http://wiki.ecmascript.org/doku.php?id=proposals:generic_functions interesting. Obviously not a live proposal, but if we ever want operators, I'm still in favor of multimethods instead of hardcoding. The current untestable spec can't stand much more complexity in its runtime semantics. If we ever get complex numbers, quaternions, etc., they should come by users defining operator multimethods after the committee has retired in victory to the same Valhalla where Dylan and Cecil are spoken :-/. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Use of redundant var
On Aug 23, 2008, at 8:23 AM, Fergus Cooney wrote: Another use I have for redeclaring variables is when I want to reuse the name but there's a clear separation between the previous use and the new use. For example, I might have a variable to amass a bunch of html snippets and then stick them in a div. I'll redeclare that variable again if I'm doing separate content for another div. It makes it explicit that there's no carry-over from above. Also, as I'm the declare-everything-first type, it also helps if I decide rearrange the code. That last point is a great one. We did talk about redundant declarations when discussing strict mode. IIRC we agreed not to punish them, mainly for the last reason and the consequent abundant use of var in several paragraphs of code where the vars have the same name and hoist to the same body scope, and nothing's formally wrong with the code. We can't have strict mode exact an inordinate migration tax, or it won't be used. We shouldn't make it too pedantic, or it will either not be used, or else waste programmer energy on non-problems or hypothetical problems. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Aug 23, 2008, at 5:45 PM, [EMAIL PROTECTED] wrote: On Sat, Aug 23, 2008 at 11:30 AM, Sam Ruby [EMAIL PROTECTED] wrote: Having Decimal.parse(2) + 3 produce 23 is not what I would call fail fast, as that is a term I would typically use for throwing an exception or the like. Point well taken. Does Maciej's followup regarding valueOf throwing solve the problem? It forces would-be Decimal users to call Decimal.add(Decimal.parse(s) + 3) (let's say s may or may not be 2 or 2). Is that a solution for ES3.1? It's user-hostile instead of future-hostile. Can we not do better, especially by not overconstraining the problem by subjecting its solution to the ES3.1 goals and schedule? Were ES designed, back in 1995, to be the language it has become, and were there time back then to have thought about how the builtin arithmetic and comparison generalizes to mixtures of decimals, arbitrary precision integers, complex numbers, matrices and polynomials, I would agree with you unequivocally. As matters stand, I'm not so sure. I've been through as many what-if's and might-have-been's as anyone. JS clearly had too much implicit magic -- Perl-envy, if you will -- to be as neatly extensible as we want, in hindsight. EIBTI, the Pythonistas say. But this need not mean explicit method calls instead of operators for any numeric extension, since that's pretty much unusable (except under SOX mandate :-/). We've often cited EIBTI in ES4 working group meetings. In general I daresay the TC39 committee is more in favor of avoiding implicit magic, especially conversions, now than ever (E4X, ECMA-357, is full of it, and it's a mess). But this doesn't mean that throwing when a Decimal is used in any not-guaranteed-to-be-numeric operand context is good. It would not be wise for equality operators, in particular, to start throwing exceptions. Could these operators simply be consistent with === for any user defined library type, and something else (a .equals() operator, say) be used to define value equality? That's incompatible, and the double-dispatched (for dyadic operators) method mapping is something we'd like to avoid in the future (wherefore multimethods). Once again, Java faced this same problem in adding BigDecimal -- and Java is strongly typed and so arguably had more leeway to add rules that make it clearer to programmers what was going on. Yet their solution was to simply create classes at the library level. BigMistake, as Cameron blogged. Java failed, C# ruled here. I think the Java analogue is instructive. In Java, primitives and objects are distinct. That's a botch, one I copied in a hurry in 1995 and regret. I should have stuck to the Self and Smalltalk sources of inspiration, but JS had to look like Java and it was easier both to implement, and to think about JS/Java bridging (LiveConnect, so-called), if I distinguished primitive string, boolean, and number from their object wrapper types. BigDecimal was apparently a clumsy enough entity that it was found to need implementation as a constructed object. This apparently backward-reasoning phenomenology is flawed. Implementors can work harder so programmers don't have to. There's no technical reason that decimal has to be a non-primitive in any language that distinguishes primitive types from first-class object types, any more than there is for strings to be non-primitive. In ES, everything is an object yet there are primitive types; this means that, when faced with a newly required constructed object type, we are tempted to slip it in as a new primitive. In the absence of extensive planning done back in the mid 1990s, I submit that the temptation is to be resisted. What extensive planning do you mean? Oh, the lack of it when I created JS. Sorry, this is bogus arguing too :-|. Five-year plans are no guarantee of success. Utopia is not an option. Lots of underused languages have over-planned designs and nevertheless have big problems (other than lack of users). Anyway, languages that do succeed in gaining users inevitably grow. Growing a language is hard but possible. Python grew, including in its numeric model and operators. In spite of harsher backward compatibility constraints, so too can JS. IEEE double is not the only conceivable number type, and indeed 32- bit int and unsigned int show through in places in JS (bitwise operators, array length). I'm not in favor of more machine types. But I think making more BigMistakes with methods only, no operators, is guaranteed to keep IEEE double the only number type that's actually used by most real-world JS programmers. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Aug 23, 2008, at 8:23 PM, Sam Ruby wrote: The remainder of the quote that was relayed to me was that spec'ing the operators would not be hard. I took it upon myself to refamilarize myself with spider monkey and implement these operators, and despite it being a decade or so since I've done any serious C/C++ coding was able to complete that task in a long weekend. You know that I'm glad you're doing this. Doesn't mean it's going to make 3.1, or that it must. I've since started updating the spec, and the changes are very straightforward and contained. You can see for yourself, most of the changes are already in there. I will look when time permits, before the next TC39 meeting. Given this, the way I would like to proceed is towards a full and complete proposal to be ready in time for people to review for the Redmond meeting. It may very well need to be scaled back, but I would much rather be in a position where the edit requests that came out of that meeting were in the form of prune this rather than once again be presented with investigate that and report back. How would a response of take the time you need, and we'll track it for Harmony; 3.1 is otherwise all but done strike you? Frankly, it sounds like moving the goal posts. You think so? I respectfully disagree, and I've been in all the face- to-face meetings. ES3.1 started in earnest this past January, with a limit scope. Decimal (already in ES4 as proposed, with operators as well as literal syntax) was not being pushed into ES3.1 until spring- time, at which time 3.1 was supposed to be technically done in July, finalized including editorial fussing and typography in September, etc., for standardization at the December GA meeting. Seems to me the push for Decimal moved some posts. Why is Decimal-or- a-No-vote being hung like a sword over the committee's head? What goes wrong if Decimal is not in 3.1, but is (especially with user- feedback-based improvements) in the successor Harmony edition within 1-2 years? When is spec freeze? When do we need to have implementations complete? Are we planning to have these implementations usability and field tested? Will adequate time be allowed to factor in feedback that is received from these tests? Let's get the implementations done and we'll see. There's no deterministic top-down command -and-control schedule here. For the open source implementations, the main thing is to get into nightly builds, get docs and blogs educating users, gather bug reports. I'm writing the spec. I've written one implementation -- or more precisely a binding to an implementation that has been well tested and made available under a very liberal license. I've run the performance tests you asked me to run. I'm ready and willing to convert the existing decNumber test suite over to whatever format is desired; I'm also ready and willing to write additional tests to cover the ES specific binding to these functions. We should talk about landing your patch on Mozilla elsewhere. IIRC Rob Sayre asked for a few things in the bug and I haven't seen your response (I may have missed it; been busy lately). The meanings of operators when all of the operands are decimal are well specified by IEEE 754R. The meaning of equality in ES3 is a bit arcane, and we've worked through that. My SpiderMonkey implementation provides access to decNumber's compareTotal method, and Object.eq (something Doug and Mark feel is necessary for other reasons) can be defined in such a way as to make use of that function. What's the Object.eq issue? I must have missed an 8am 3.1 call. :-/ What's left is figuring out is the syntax for constructing decimals from strings (Decimal.parse sounds fine to me, how about you?), and from binary64 floating point numbers (Number.toDecimal sounds fine to me, how about you?). I like those names, FWIW. And to decide whether binary64 numbers get converted to decimal128 when they are mixed, or if it is the other way around. That is important to get right. Igor Bukanov and I both sounded off on this list as against any mixing of decimal128 and binary64 that degraded toward binary64. So I'm pleased as punch with your new thinking. I was originally pursing the latter, but based on feedback, I'm seriously considering the former -- with the proviso that the conversions be exact and correct rounded, to the limits of the precision supported by decimal128. This approach not only has the advantage of being exact and correct, it also obviate the need for use decimal. Maybe, except writing 123m all over is enough of a drag that most people won't. There still could be a case for 'use decimal'. How's the new approach (contagious decimal128) working out in the code? /be___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Aug 24, 2008, at 12:51 AM, Maciej Stachowiak wrote: But this doesn't mean that throwing when a Decimal is used in any not-guaranteed-to-be-numeric operand context is good. Actually, throwing from valueOf would have the opposite effect. Of course, and my not- was a thinko. I meant guaranteed-to-be- numeric. Having memorized a lot of ES3, including where the preferredType hint is not number, I was not trying to make the opposite point within the same mail message. We could throw from valueOf, but at least you and I agree it would be better to avoid any such a seemingly-rushed, library-only, user- hostile Decimal. Waldemar and I said so at the Oslo meeting, and Sam agrees. I am interested to see what Sam can pull off, in code more than spec. I don't doubt the spec can be done, given design decisions from IEEE P754 and some freedom to match JS design impedance. I'm concerned we won't have time to give such a purportedly user-friendly Decimal sufficient user testing. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Aug 24, 2008, at 6:18 AM, Sam Ruby wrote: A modest request: if the code could be reviewed and feedback provided to me with sufficient time for me to address the comments and the code to be integrated into a nightly build, by default disabled, in time for the Redmond meeting, I would appreciate it. Set the review flag to my bugzilla id -- othewise I won't see it in my request queue, and I'll probably forget to go review it on my own. Thanks. Let's posit for the moment that adding two nickles and calling toString() on the result produces 1.10 Where'd the buck come from? ;-) Ok, I'm with you so far... Furthermore assume that 1.10m 1.09m and that 1.10m 1.11m. Given the above, as well as your knowledge of ES history, what would you expect the results of evaluating the following two expressions to be: 1.10m == 1.1m true. 1.10m === 1.1m true, but there's a weak case for false if you really insist that the significance is part of the value. If we make the result be false, then people who advocate always using === instead of == to avoid implicit conversions would be giving bad advice to Decimal users. I'm sticking with true for the reason given below. Depending on your answers, there may be a followup question. Guy Steele, during ES1 standardization, pointed out that some Lisps have five equality-like operators. This helped us swallow === and !== (and keep the == operator, which is not an equivalence relation). Must we go to this well again, and with Object.eq (not an operator), all just to distinguish the significance carried along for toString purposes? Would it not be enough to let those who care force a string comparison? /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Look Ma, no this (was: ECMAScript Harmony)
Polls are not so good, compared to reasons. Could you give your rationale and talk about the trade-offs, in your experience? /be On Aug 24, 2008, at 7:36 PM, Peter Michaux wrote: On Sun, Aug 24, 2008 at 6:05 PM, Brendan Eich [EMAIL PROTECTED] wrote: On Aug 24, 2008, at 4:09 PM, Mark S. Miller wrote: [snip] Others on this list should comment on class-private vs. instance- private. If this is just a poll then I'm all for instance-private. Peter ___ 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: Es-discuss - several decimal discussions
On Aug 24, 2008, at 10:02 PM, Mark S. Miller wrote: Let's say you did that -- make a special case for NaN but not for -0. Let's say you use this Map to build memoize. Now let's say someone writes a purely functional function F such that F(0) is 3 and F(-0) is 7. Let's say G is memoize(F). Would you find it acceptable for G(0) to sometimes yield 3 and sometimes 7? I'd file a bug, or find a better memoizer :-). Quality of implementation eager beavers can use Math.atan2 to tell -0 from 0, just as they can use isNaN or x !== x. Yes, this is gross. I'm in favor of Object.identical and Object.hashcode, maybe even in ES3.1 (I should get my act together and help spec 'em). Just not particularly on account of Decimal, even with equated cohort members. I still agree with Sam. And as always,hard cases make bad law. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Look Ma, no this (was: ECMAScript Harmony)
On Aug 24, 2008, at 8:40 PM, Peter Michaux wrote: Polls are not so good, compared to reasons. Could you give your rationale and talk about the trade-offs, in your experience? You summed it up nicely with the hat trick: It's a nice hat trick: privacy, higher integrity, and semantic reuse all in one. I'm not sure there will be anyone who can explain that any one OOP system is right and the others are less right. That is what I imagine will make consensus on this topic very difficult.. Every OOP language has a different set of OOP features so there doesn't appear to be an objective (ha!) winner after decades of programmers exploring OOP. The fact that this is really a subjective issue is why your initial request for comments seemed somewhat appropriate for a poll. It is a what do you like question. And yet you go on to make a great non-aesthetic case, with particular and pointed reasoning. (The delegation boilerplate for Java has-a cases scores!) Thanks. I'm still inclined the same way as you and Mark (and I believe Waldemar, at least at Oslo). IP+ZI FTW! ;-) I've talked about both privacy and inheritance when you only requested about privacy but the two issues are closely related. Indeed. Thanks again for the thoughtful response, /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Look Ma, no this (was: ECMAScript Harmony)
On Aug 24, 2008, at 9:44 PM, Kris Zyp wrote: I am surprised this is up for debate, I would also think that we would want instance-private by default. We can debate lots of things, some that might actually be in play. AFAIK this one is not decided in the committee (it's way too early), but IP does have some strong proponents. AS3, JScript.NET, and Waldemar's original ES4/JS2 work all had CP. Java has CP. So do C++ and C#. It should not come as a surprise, therefore, if CP has at least to be dealt with by some rationale for IP over against CP. Smalltalk rules won't cut it ;-). I'm happy to have a little debate on this topic, given the different precedents. I'm wondering why you think there's no question. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Look Ma, no this (was: ECMAScript Harmony)
On Aug 25, 2008, at 12:34 AM, Peter Michaux wrote: On Sun, Aug 24, 2008 at 9:44 PM, Kris Zyp [EMAIL PROTECTED] wrote: Desugared from: class Point { private var x = Math.random(); function getX(){ return this.x; } ... } Is there any need for the this.? Some languages allow this.x to get out from under the shadow of a local x inside getX. I don't think it is necessary to be able to escape such shadowing and actually increases confusion. If a method is many lines long then the reader may forget that x is local and not the instance variable. I would just call the local variable locx or xx or something different. I would actually rather see the this. shadow escaping be disallowed. That might be a good idea. The bigger question is whether |this| remains at all. The desugarings we tend to write on whiteboards use |let self = ...| or similar and | self| as the new |this| -- but of course that might collide with a necessary inner or outer name. It would be better to gensym the name, but who has time at a whiteboard? To refer to the instance in the sugared language, and there are valid use-cases for doing so, we should use |this|. There's no point in introducing a new keyword. Which gets to a point you raise later, about var in class being confusing. If class is the new, higher integrity constructor function that induces instance-bound frozen methods, etc., then its syntax (by the similarity principle I adumbrated earlier) *should* mimic function: class Point(x, y) { // parameters to constructor here let r = Math.sqrt(x*x + y*y); let theta = Math.atan2(y, x); function getX() x; function getY() y; // etc. } var or const could be used too, because they can be used in function bodies. Class body *is* constructor code. Similarity is good because it builds on JS programmers' knowledge of functions, but provides incrementally better semantics for the similar syntax. Programmers get the carrot, not the stick of gratuitously different syntax. It will take more than a 2D point class to make the case, but this was along the lines of the Oslo discussions on the third day, to desugar as Mark proposed on the first (and showed in his post at the head of this thread). In the above code snip it seems that properties will be public unless listed as private. In the security world, whitelisting is considered a best practice as blacklisting can accidentally leave things out in public that should not be. Not everything in JS is security-critical. JS is used in single-trust- domain embeddings, but even on the web, the BD programming by way of the security root password to the tattered just a scripting language constitution seems like a power-grab :-P. I mixed three kinds of technical politics there, but they are all relevant. Different parties are concerned about the common good, but we don't all agree on the common good. Python and Smalltalk don't have private methods by default (or at all), just to pick two examples. Should classes as better constructors have this bias? I'm not saying no, I reserve judgment. It seems to me much depends on the module system, if there is one (and there had better be, since in spite of being the inevitable source of addressing and loading semantics, the script tag is not enough for in-language modularity). What about the following two options: class Point { private x = Math.random(); public function getX(){ return x; }; } Verbose, please pick a default. Making people type private all the time is going to get old (if you think 'function' is too long...). var Point = class { private x = Math.random(); public getX = function(){ return x; }; }; This shows a separable and good idea: first-class classes. BTW, you probably want 'const Point = class { ... }', and 'class Point...' should make a const binding by default (unlike a function definition -- another upgrade). Another separable point to debate: resolved, classes should freely nest (in other classes and functions) and generate new entities each time they are evaluated. Just like functions (ignoring or removing the joined function object option from ES3). If only one option could be included I'd *much* prefer the final option as var could be changed to let so I control the class's scope better. That's not to say we shouldn't have the named form of class, any more than we shouldn't have named functions. Named functions are a special form, as close to let rec as you get in JS. You can have mutually recursive named functions call one another freely, making forward refs, due to hoisting. You also get the intrinsic name, useful for diagnostics at runtime and harder to infer (really guess, worst-case pick the name of the most relevant binding) for anonymous functions. In either of the last two cases, I imagine that the Point variable is pointing to a
Re: Look Ma, no this (was: ECMAScript Harmony)
On Aug 25, 2008, at 6:39 AM, Kris Zyp wrote: I am surprised this is up for debate, I would also think that we would want instance-private by default. We can debate lots of things, some that might actually be in play. AFAIK this one is not decided in the committee (it's way too early), but IP does have some strong proponents. AS3, JScript.NET, and Waldemar's original ES4/JS2 work all had CP. Java has CP. So do C++ and C#. It should not come as a surprise, therefore, if CP has at least to be dealt with by some rationale for IP over against CP. Smalltalk rules won't cut it ;-). I'm happy to have a little debate on this topic, given the different precedents. I'm wondering why you think there's no question. /be I'm sorry, I had misunderstood. I was thinking CP meant one variable per class (like indicated by static), but CP means the scope of who could access the private object property. This is a question worthy of debate. Thanks, Yeah, that confusion happened briefly in Oslo. Class-private vs. instance-private instance variables might be the long-winded solution to ambiguity. CPIV vs. IPIV? Yuck. Properties of the class constructor, with appropriate attributes, AKA class statics, are not controversial AFAICT. There ought to be sugar. It might well use the static keyword. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Aug 25, 2008, at 4:29 AM, Sam Ruby wrote: If Decimal is an object type, then typeof 1.0m == object is good for a couple of reasons: * Future-proof in case we do add a primitive decimal type, as ES4 proposed -- a peer of double that shares Number.prototype; typeof on a decimal would return number. See below for the possibly-bogus flip side. What would be the upside to such an approach? I can see the next-edition-of-ES-that-provides-decimal (my working assumption still is 3.1 whatever that may be called, others may be understandably skeptical) only providing a Decimal object, and with that addition the language with respect to decimal being considered a steady state that not need to be revisited in subsequent editions. Yes, I was being a little too generous with the possibility of a primitive making a come-back. If we evolve by adding Decimal as an object typeof-type, that's it. Probably better this way in the long run, the operator extensions should inform our evolving thinking on generic arithmetic and multimethods. * Analogous to RegExp, which has literal syntax but is an object (RegExp is worse because of mutable state; Decimal presumably would have immutable instances -- please confirm!). I'd prefer if Decimal instances in ES were considered immutable and automatically interned. By the latter, I simply mean that new Decimal(1.0) === new Decimal(1.0). The spec should say this. Decimal.prototype would be extensible and not sealed, however, just as other standard constructor prototype objects are. A bit of a challenge in the spec, and in implementations that make an unconstructed primordial instance be the class prototype, but not insuperable (hand-wave alert). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Aug 25, 2008, at 6:45 AM, Mark S. Miller wrote: maybe even in ES3.1 (I should get my act together and help spec 'em). (I will help on identical/hashcode, btw -- think we're agreeing vehemently ;-).) Just not particularly on account of Decimal, even with equated cohort members. I still agree with Sam. And as always,hard cases make bad law. What is it you and Sam are agreeing about? I lost track. That if we make cohort members == and ===, telling anyone who still wants to distinguish 1.0m from 1.00m to use compareTotal is good enough. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: eq, eql, equal [Was: Es-discuss - several decimal discussions]
On Aug 25, 2008, at 6:58 AM, Mark S. Miller wrote: On Mon, Aug 25, 2008 at 6:50 AM, P T Withington [EMAIL PROTECTED] wrote: FWIW, as a user, I've always assumed: == : equal [1] [1, 2] == [1, 2] // yields false This makes me sad, but some day there might be ways to attach multimethods (opt-in basis) that make it all better. Just a thought. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Look Ma, no this (was: ECMAScript Harmony)
On Aug 25, 2008, at 12:23 PM, Peter Michaux wrote: To refer to the instance in the sugared language, and there are valid use-cases for doing so, we should use |this|. There's no point in introducing a new keyword. If there is a need to refer to the instance then this does make sense. What would be a great success if if there is just no need for this at all. It certainly seems possible to avoid. I don't think so. Standard patterns of delegation (visitor, double- dispatched dyadic operators) must pass |this| whole and intact. Now there is another problem: differentiating between which variables are local to the constructor function (that is, transient and garbage collected after the constructor function is returned (don't know the technical name for these variables)) Temporaries. and which are properties of the resulting returned object. True temporaries might need explicit block scope to avoid being entrained in closures. Requiring the programmer to use both public and private as I did below might be a solution (though you thought it is verbose) so that it is clear which variables are part of the constructed objects. But the private vars would not be temporary. They would need to live as long as the instance. It seems to me you're mixing lifetime with visibility. I suggest at least a couple DOM widgets are used (e.g. tabbed pane, dragdrop list, sortable table) as test examples when discussing class sugar seriously. The DOM is a big part of the JavaScript world, after all. Great idea. A lot of Ajax widgets, e.g. Dojo, use their own inheritance models, often based on copying properties (sometimes based on prototypes; in the case of Dojo's MI, both!). Copying is fine for a zero-inheritance classes-as-sugar proposal. The prototype stuff, as Kris points out, is different. In ES3 a nested function is private inside the outer function. So there is some sense of private by default already. Lexical scope is great. You have a point. No one seemed to response to my post in the thread about modules but module should not equal file as HTTP is still expensive and programmers want to concatenate and minify their scripts. Oh, absolutely. I made the point in several posts, and Ibad picked up on it: addressing and loading are outside the core language. The inside part that's left is about how the importer names (or does not name) the module, how the module provides what the importer requires, how eagerly linking occurs, whether cycles are allowed (better be!), etc. The upshot is that stuff has to be loaded already. You can't block a script mid-evaluation and go service events (violating run-to- completion or else locking up some or all UI) to load a remote file on demand. The only unfortunate thing about function is they are not really functions. Ok, I will bite: what are they? Another separable point to debate: resolved, classes should freely nest (in other classes and functions) and generate new entities each time they are evaluated. Just like functions (ignoring or removing the joined function object option from ES3). Great! I phrased this as a proposition to debate pro or con. I didn't mean to say it was resolved (but I hope it will be, in Harmony). There are deeper waters to do with types, Yes. The parent-child windows issue both declaring the same or different class Foo seems like an important detail. Perhaps provably making nominal types useless or at least as awkward as instanceof? No, nominal types have their uses. In two disjoint globals, loading code defining the same nominal type should result in two types, not one -- we don't want to trust the name, or compare the contents. The name would simply be qualified by some kind of global identifier or pathname. Nominal type use-cases for security, which I've mentioned before, include auditors (http://www.erights.org/elang/kernel/auditors/) and hybrid information flow systems (http://www.ics.uci.edu/~franz/Site/ pubs-pdf/C46Prepub.pdf, see figure 3). When you need type relations and equivalence based on name bound by special form, it's hard to do without. As Mark pointed out in Oslo, nominal types plus lexical scope let human and machine auditors know *exactly* what implementation(s) a class has. One can make nominal types via branding in a structural type system. There's more to say here, later. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Aug 25, 2008, at 1:59 PM, Mark S. Miller wrote: On Mon, Aug 25, 2008 at 1:20 PM, Brendan Eich [EMAIL PROTECTED] wrote: On Aug 25, 2008, at 6:45 AM, Mark S. Miller wrote: What is it you and Sam are agreeing about? I lost track. That if we make cohort members == and ===, telling anyone who still wants to distinguish 1.0m from 1.00m to use compareTotal is good enough. I agree with this if-then, but why not recommend Object.identical instead? Cuz it's more work for 3.1 than needed, and compareTotal is required by P754 IIRC. Either's good, Object.identical is better, but when in doubt... Yeah, I'm still thinking in Decimal for ES3.1 terms here. In any case, is there any general agreement about *whether* 1.0m == 1.00m or 1.0m === 1.00m? This is where I lost track. Yes, I believe Sam and I agree on those holding true. As you note, typeof x == typeof y x == y = x === y, so anything else will break that relation, and it's not just an ideal form: users, especially those taught to avoid == in favor of ===, will have our heads if 1.0m != 1.00m. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: local
On Aug 25, 2008, at 3:00 PM, Ingvar von Schoultz wrote: ...we'll have to write something like this? const { DatabaseName, DisplayCount, ... Ten more ... } = Debugging ? { DatabaseName: TestDatabase, DisplayCount: 5, ... Ten more ... } : { DatabaseName: RealDatabase, DisplayCount: 15, ... Ten more ... }; Very often conditionals aren't that simple. It'll get ugly. The new awkwardness does makes sense in big projects, but only there. Another way of looking at this is to say that const should be write once, not necessarily initialized in the declaration. Then you could write const DatabaseName, DisplayCount, /* ... ten more ... */; if (Debugging) { DatabaseName = ...; } else { etc. } This was ES4's const. At the Oslo meeting there was strong opposition to write-once. The reasons were not clear to me (could be my fault). Here you show a reason for write-once. The alternatives are destructuring from a ternary (as you showed), falling back on var (losing), or inventing some super-const binding form that escapes its block (not in the cards). let blocks and let expressions do not have solid support in TC39. I have no opinion on whether let blocks and let expressions are useful, but you could make them very cheap by dropping the intricacies that make let(x=x){} refer to two different x'es: let (a = x) {...} desugars to {let a = x; ...} If by cheap you mean easy to implement, there would be a savings to compiler costs, but not at runtime. let (a = x) a; desugars to {let a = x; a;} Sorry, no: the latter is not an expression, the former is (if you remove the ; at the end). As a bonus everyone will rejoice at the lessened cognitive burden of intricacies. But then why have the let block form at all, since let declarations are sweet enough. The case for let expressions remains even if you eliminate the let binding rule, since they are expressions. You'd have to invent generalized BCPL- or Algol-68-like expression language support, which is also not in the cards (I mentioned the idea briefly in Oslo, more as a joke or an aside). Of course Schemers will find a let with these semantics confusing. Clearly it needs a different name. How about... local? :-D Sorry, no; please stop nagging. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Aug 25, 2008, at 4:10 PM, Mark S. Miller wrote: are shallow generators implementable by a local cps transform? Yes, the local evaluation (inside the generator function) is the only place that needs to be CPS'ed to allow yield in any expression or statement context. This approach would seem relevant to adding generators by adding new semantic state. But would it help us understand how to add generators by a local code transformation? Why does this matter? Changing any future ES spec to use CPS is a semantic state shift, and a very big one. The plan (designed and implemented by Dave) for specifying generators in ES4 was to use delimited continuations in the SML reference implementation. It's not pretty, but you can CPS-convert generators. Here's a concrete desugaring (souring? :-P) example based on JS1.7, not ES4 (no iterator namespace, ugly __iterator__ name instead): function simple_range(n) { for (let i = 0; i n; i++) yield i; } function simple_range(n) { let i = 0; return { __iterator__: function () { return { next: function () { if (i == n) throw StopIteration; return i++; } } } }; } Object.freeze on the returned iterator object omitted ;-). Adding send, throw, and close also left as an exercise. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Consistent decimal semantics
On Aug 25, 2008, at 4:41 PM, Waldemar Horwat wrote: We're going round in circles on a few issues surrounding Decimal. It seems to me people have reached the conclusion you already did on ===. I'm not sure anyone advocated otherwise (I've missed most 3.1 calls lately, so can't be sure). Some of these have clear resolutions; others have a little wiggle room. Here's my summary: Thanks, the FAQ format is helpful. I agree with your answers, but I have a couple of questions. - Should decimal values behave as objects (pure library implementation) or as primitives? If they behave as objects, then we'd get into situations such as 3m != 3m in some cases and 3m == 3m in other cases. Also, -0m != 0m would be necessary. This is clearly unworkable. What should be the result of (typeof 3m)? [snip] - What should cross-type === do on 5 === 5m? These objects are of different types, so it should return false. Confusion: 5 is of number type (a primitive type, typeof agrees), so These objects should have been These values -- right? Sam and I, not going in circles (much), agree that typeof 3m should be object, and that we add hardwired operator support for such Decimal objects. - How should mixed type arithmetic work in general? There are a few consistent design alternatives: 1. Always disallow it. For consistency you'd have to disallow == between Number and decimal as well. This was what Igor Bukanov and I were advocating last week. 2. Allow it, converting to the wider type (Decimal128). There are a couple design choices when doing the conversion: 2a. Convert per the IEEE P754 spec: 5.1 turns into 5.099644728632119949907m. This is how most programming languages operate (C++, Java, Lisp, etc.) when converting among the built-in floating point values (float - double etc.). (I'm asking anyone who thinks so, as well as asking for your opinion:) Better than alternative 1? If so, why? 2b. Convert the Number to a string and then to a Decimal: 5.1 turns into 5.1m. As a special case, -0 would turn into -0m. This might work, but I haven't thought through the implications of this one. Interesting idea. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Look Ma, no this (was: ECMAScript Harmony)
On Aug 25, 2008, at 4:57 PM, Peter Michaux wrote: There needs to be a way(s) to distinguish which variables have which lifetimes and visibilities. We have ways already: explicit blocks containing let-declared temporaries; your public to make things visible outside their lexical scope. Rules to be worked out, I am going fast here (don't slow me down ;-), but I do not see the point in reinventing wheels or mixing them into hybrids. The following is no good class Foo() { BTW, no need for () after the class name -- a bit more sugar. var temp = 0; var priv = 1; var pub = 2; } It could be class Foo() { var temp = 0; private priv = 1; public pub = 2; } In the above example, temp will be garbage collected and there is no use in the private priv variable and it could be garbage collected too. Why reinvent the wheel with private? Functions outside of classes do not capture any such declared bindings. class Foo { var temp = makeBigObjectGraph(); var nontemp = computeSomeResult(temp); var nontemp2 = computeAnotherResult(temp); function private_method() {...} public function public_method() {...} } This is bad. Without inventing more syntax, one way out is to write class Foo { var nontemp, nontemp2; { let temp = makeBigObjectGraph(); nontemp = computeSomeResult(temp); nontemp2 = computeAnotherResult(temp); } function private_method() {...} public function public_method() {...} } There are other ways around the unwanted entraining of the big object graph. You could ask for a constructor function inside the class, as AS3 and ES4 support. But it's still possible to entrain too much in such a function, and you can't initialize the member vars directly in their declarations (this combined with non-null types led to the settings syntax in ES4). So really, caveat hacker. Closures can hang onto too much memory if you are not careful. The situation changes when a public method exists. class Foo() { var temp = 0; private priv = 1; public pub = function() temp + priv; } Now temp is captured in the closure of pub and so temp is effectively instance-private. So the private keyword isn't necessary at least in terms of lifetime as the following is the same. class Foo() { vartemp = 0; varpriv = 1; public pub = function() temp + priv; } This last example, no private keyword, (Whew.) works if instance-private is desired. If class-private is desired (I hope not! as I explained before) then the second to last example above would be required. In which case var works like Ruby's private (instance-private), private works like Ruby's protected (class-private) This reminds me of an idea from Dave Herman and Sam Tobin-Hochstadt to add private syntax for generating Name objects bound to lexical names (after define-local-member-name in PLT Scheme): private var priv = 1; Not exactly the same syntax as you sketched, but you could also separate name generation from use: private priv; var priv = 1; and make other uses in the same lexical scope of the (impossible to forge as a string) Name object mapped to the 'priv' lexical name. This could be used for class private, C++ friend, and other such use-cases. and public is like everyone's public. :-) So the issue may not be choosing between instance-private *or* class-private. That's what I was getting at in an earlier message with the generated Names for class, friend, etc. private. JavaScript will have instance-private thanks to closures. The question becomes is class-private also desirable, worth the extra keyword and complexity both to learn and to debug? It's a good question. I think the ability to have two modules in one file means modules will need to name themselves. That is they will need to be declared with a name like module foo { // ... } or var foo = module { // ... }; The importer could rename things but somehow the importer will have to use the name foo to at least start importing. I will let Ibad^H^H^H^HIhab jump in here ;-). By cycles you mean module A using module B which uses module A? Late linking would required to allow cycles, correct? Yes. Any early linking would mean no cycles allowed, leaving us with second-class modules of the PLT Scheme kind (PLT Scheme has a first- class module system too, called Units, which does allow cycles). At this point I should summon and defer to Dave Herman (who may be a bit too busy to respond, but here's hoping). Also perhaps the foo variable may reference different module objects at different times. The var foo could be rebound, but modules by default should have higher integrity than that. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Aug 25, 2008, at 6:15 PM, Mark S. Miller wrote: Thanks, that helps a lot. But shouldn't that i == n be !(i n) since it's a transform of the original i n? Sure -- was going fast (other work competing ;-). On Thu, Aug 21, 2008 at 11:31 PM, Dave Herman [EMAIL PROTECTED] wrote: Can't be done without defining the entire language in CPS. Yes, it's shallow, but a captured activation can involve any arbitrary combination of expressions other than function call. Dave, is the violent transform of the for-loop above the kind of rest-of-the-language transform you were referring to? Answering for Dave: yes. If so, isn't this only an issue for control structures (including , ||, and ?:)? What other elements of the language might need to be turned inside out this way? Or have I misunderstood what you're getting at. As in Python 2.5, JS1.7 and up support yield expressions too. These return values and resume with new values when the generator is continued via next (which sends undefined) or send(v) (arbitrary v). The simple_range example I showed happened to use yield as an expression-statement. I don't expect we'll CPS-transform any future ES spec, but you are entitled to pain if you like it ;-). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Look Ma, no this (was: ECMAScript Harmony)
On Aug 25, 2008, at 7:07 PM, Erik Arvidsson wrote: I've been quiet on these threads for a long time but i just wanted to emphasize Kris's point. Whatever we decide to desugar the class syntax into I think it is very important to get this right. We need to make classes work with existing prototype based inheritance chains. I would consider it a failure if I cannot create a class that inherits from dijit.TabPane or from a Prototype UI component for that matter. Can you define inherit more precisely? If it's a matter of giving classes .prototype objects, perhaps this could be done (it's attractive since the built-ins, Object, Date, etc., are classes as well as constructor functions, which have prototype objects). I would also like to know more about the arguments why people seem to be set on a zero inheritance class model? Does that imply that one can still achieve inheritance using prototypes or does it mean that inheritance is not desired at all? No, prototypes are here to stay. There's even Object.create to relieve prototypers from having to write constructor functions. The desire to explore ZI is two-fold: 1. It may help the committee to see the smallest possible proposal, and work up from there to SI and MI. 2. It may help the language to avoid adding another kind of inheritance than prototype-based delegation. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Aug 25, 2008, at 8:51 PM, Mark S. Miller wrote: How important is it that yield be an expression rather than a statement? It seems like a sibling of return and throw, so I don't think anyone coming to them afresh would be surprised if yield were a statement. This is and was not a clean-slate exercise. We both followed and gave feedback to Python in doing this work, because the Python and JS communities overlap significantly, and the languages share certain stylistic and substantial features (not all, but enough). The goals include reusing the Python open-source/python-dev experience and the developer brainprint. yield as an expression form is important for so-called co-routines, where you can call gen.send(val) to resume a generator the val becoming the result of the last yield expression; you can also gen.throw(exc). Finally, and this is possibly the most useful, gen.close() will be called in JS when a generator used in a for-in construct. With close called from for-in, cleanup can be automated that otherwise can't be done without Python-style ref-counting/GC, Java-style finalization, or worse -- complexities we wish to avoid in any ES standard. Calling gen.close() on an open generator forces a return from the last yield. This has the desirable property that if the yield is in a try, any relevant finally clauses will be run. (Return from generator throws StopIteration, as usual for iterators; a generator can't return a value.) Background reading: http://mail.python.org/pipermail/python-dev/2006-August/068497.html http://mail.python.org/pipermail/python-dev/2006-August/068498.html http://mail.python.org/pipermail/python-dev/2006-August/068450.html One use of generators, which Neil Mix wrote: Threads in JS: http://www.neilmix.com/2007/02/07/threading-in-javascript-17/ Source to read: http://www.neilmix.com/demos/js17threading/example.js http://www.neilmix.com/demos/js17threading/Thread.js These use send and yield expressions heavily. The es- [EMAIL PROTECTED] archives at https://mail.mozilla.org/pipermail/es-discuss/ best searched with Google site:mail.mozilla.org search, have a number of threads tracing the evolution of generators. Besides Igor Bukanov's work to simplify the close mechanism by eliminating GeneratorExit, Chris Hansen of Google made the crucial proposal to automate close only from for-in constructs (not from GC). Generators are in JS1.7 (Firefox 2). Sugar in the form of generator expressions, as in Python 2.4, are in JS1.8 (Firefox 3). My port of Peter Norvig's Sudoku solver, which uses genexps: https://bugzilla.mozilla.org/attachment.cgi?id=266577 I believe Pythonic generators have been the most useful, if not most widely used, of the extensions that we have shipped since JS1.5 (ES3 + getters and setters). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: dynamic class idiom
On Aug 26, 2008, at 2:49 PM, Dave Herman wrote: I noticed a little idiom supported by classes-as-values: (new (class() { ... })) This essentially builds an object whose properties can be computed in an arbitrary statement context-- with loops or what have you. You might call this a dynamic singleton pattern; a throwaway factory. It's not a global singleton like in Java; it's just an ordinary expression so it might be called by a function or whatever. Probably everyone involved favors first-class classes -- first-class meaning classes as values (not only as named defining forms), nestable. I hoped so in reply to Peter yesterday. Worth a little sugar? E.g.: object { ... } ~=~ (new (class() { ... })) Does not say class, seems to save only a few chars (you over- parenthesize new ;-). Wait for demand? or maybe to conserve keywords (a bit backwards-incompatible): new { ... } ~=~ (new (class() { ... })) This is not incompatible at all, since an object initialiser has no [[Construct]] in ES3, so cannot be the operand of new. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: dynamic class idiom
On Aug 26, 2008, at 4:16 PM, Dave Herman wrote: Does not say class, seems to save only a few chars (you over-parenthesize new ;-). Wait for demand? It's not about saving chars so much as introducing a new (lightweight) semantic concept: an object initializer that is a block rather than a table mapping names to expressions. Not saying `class' is the point. But you'd say class if you needed to define the operand to new for other uses, or for some other reason motivating against this lightweight form. So the concept seems to have two names when generalized slightly. Specializations can have special names, don't get me wrong. But object is way overloaded. I over-parenthesized because I wasn't sure how it would parse if you said e.g. new class() { ... }.foo That should be unambiguous, and work as this does in ES1-3: new MyClass(arg).foo The grammar goes to some lengths to group (new MyClass(arg)). or maybe to conserve keywords (a bit backwards-incompatible): new { ... } ~=~ (new (class() { ... })) This is not incompatible at all, since an object initialiser has no [[Construct]] in ES3, so cannot be the operand of new. Right, but that means that existing code isn't using this form, so you could steal this special case; then the argument to `new' would have to be an expression that didn't start with '{', just like expression statements. It's backwards-incompatible but since the current syntax only leads to a useless error, I doubt real code is using it. We consider such guaranteed errors to be unused, and call changes to claim the syntax backward-compatbile. At least we did in the ES4 WG. ES3 chapter 16 allows implementations to extend in this way, too. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: opt-out local scoping
On Aug 28, 2008, at 12:14 PM, Dave Herman wrote: I interpreted Erik's point to be that the binding of `this' is not lexically scoped, so it would be useful to have a lexically scoped variable initially bound to the global object. IOW, if I write: this.print(blah blah blah) and then I refactor the code to say: (function() { this.print(blah blah blah) })() it breaks. It happens not to break, because ES3 requires a null |this| for such calls, where the null is later replaced by the global object. obj = { method: function () { this.print(blah blah blah); }, print: function () { print(not the print you want); } }; obj.method(); would break, though. We've been trying to fix the ES3 null-global rule for a while. Any change is an incompatible change, but the current rule leads to unintended global mutation and capture bugs. By contrast if I have a standard library binding `global' that's bound to the same thing as `this' at the top level, then I can write: global.print(blah blah blah) and the same refactoring: (function() { global.print(blah blah blah) })() continues to work the same. But there's no need for a special keyword or anything like that. Indeed, Doug Crockford proposed at the January TC39 meeting this year to make 'this' act like a lexically bound variable, with the only magic to it applying to the case of obj.method() call expressions (and variatons, obj[name] where name = 'method'), where 'this' would be overridden -- if you will, a shadowing 'this' would be bound to obj. I liked Doug's proposal quite a bit. I do not see anything like it in ES3.1, but I'd like to see it in Harmony. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: opt-out local scoping
On Aug 28, 2008, at 1:23 PM, P T Withington wrote: I'd like to have a syntax where this is _not_ implicitly bound. One idea would be to riff on default arguments: function example (receiver=this, ... Why wouldn't you use |this| for the parameter name? We did for type- annotating |this| in various proposals. Some functions have a bound |this| when you extract them. Such override attempts would fail. Throw or fail silently? /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: opt-out local scoping
On Aug 28, 2008, at 2:59 PM, Ingvar von Schoultz wrote: Dave Herman wrote: Reformed `with' depended on type annotations and structural type syntax, which are undergoing discussion. So I think reformed `with' is up in the air for now. I find it odd that reformed |with| required such exact type annotations, when nothing else does. Please read http://wiki.ecmascript.org/doku.php?id=proposals:reformed_with the last paragraph in particular. It would seem that these are very similar, from an early-binding viewpoint: var {a, b, c} = fn(); x = a; var obj = fn(); x = obj.a; with (obj : {a, b, c}) { x = a; // Desugars to obj.a } Your example includes neither type constraints nor mutation. Equally it would seem that disambiguating syntax would allow early binding, if it were enforced: with (obj) { x = .a; // Desugars to obj.a New syntax could solve the ambiguity problem, but not the type variance problem. /be y = a; // From the lexical scope } -- Ingvar von Schoultz ___ 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: Sugar unrelated to macros -- Was: Re: Sugar
On Aug 28, 2008, at 3:26 PM, Ingvar von Schoultz wrote: Macros and functions are very, very different. My proposal has only regular, run-of-the-mill functions. They don't have do have, right? parentheses around the arguments, but this detail doesn't make them in any way related to macros and their problems. If you mean hygiene, that is not a practical problem so much as a theoretical one. Dave knows a lot about this topic, so I'll defer to him. I find it disconcerting that this list will so easily brush off proposals with some vague comment about something never proposed. Please cut the this list collective guilt assignment. Felix [EMAIL PROTECTED] replied identifying your idea with Python decorators, and you did not reply to him. Was his reply either disconcerting or a brush-off? No. Keep your arguments with individuals focused on individuals with whom you have a bone to pick, or better yet, avoid ad hominem (ad listinem ;-) arguments altogether. /be Ingvar Ingvar von Schoultz wrote: Dave Herman wrote: The following would let people create syntax sugar for their favorite paradigms. I really have to suggest you learn about macros before trying to reinvent them. This reading list is a good start: http://library.readscheme.org/page3.html The idea is to avoid the unsolved problems of macro hygiene. That's why the arrangement has only function calls, no macros. ___ 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: Sugar unrelated to macros -- Was: Re: Sugar
On Aug 28, 2008, at 5:35 PM, Dave Herman wrote: If you mean hygiene, that is not a practical problem so much as a theoretical one. Dave knows a lot about this topic, so I'll defer to him. No, hygiene is most certainly a practical problem! *Lack* of hygiene is a problem. My statement in reply to Ingvar's citing problems with macro systems was that, if he meant by problems anything like implementing hygienic macros, then building such systems is a solved problem for certain languages -- albeit without complete formalization in theory. This is not to say hygiene being supported in Scheme transfers to JS, of course. Ingvar's sugar proposal seems free of capture problems, at a glance, even if sugar definitions nest. But a more complete proposal would be needed to be sure. I was making a few assumptions from the examples. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Strict undefined this
#c wins by maximizing TC purity, utility, and safety. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Sugar
On Sep 3, 2008, at 3:11 PM, Peter Michaux wrote: On Wed, Sep 3, 2008 at 8:55 AM, Dave Herman [EMAIL PROTECTED] wrote: As I've said, macros aren't on the agenda for this go 'round. Is there an official wiki location which states what the committee has agreed upon for Harmony? Not yet. The agreements in Oslo were summarized in my ECMAScript Harmony post, and we've corresponded here since then about types, classes as sugar, etc. For example, if it is definitely known that macros and/or meta-programming is unanimously off the table by those with a vote then it would save a lot of energy. Why not discuss these or other future topics if you have the interest? This is es-discuss, it's not targeted only at near-term discussions. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Call for opinions: attribute defaults and renaming flexible
On Sep 3, 2008, at 10:51 PM, Mark S. Miller wrote: On Wed, Sep 3, 2008 at 9:49 PM, David-Sarah Hopwood [EMAIL PROTECTED] wrote: I don't see why any special case is needed here, or why removing it would require splitting [[Deletable]] from [[Configurable]]. Suppose that [[Configurable]] = false prevents a writable data property from being deleted or changed to non-writable. What compatibility problem does this introduce? ES3 had no way for user code to change attributes, so I don't see how there can be a compatibility problem. As I said in an earlier question from Ingvar on the same issue: Legacy demands that new properties added to the global object by assignment or top-level declarations Not by assignment -- only by var or function declaration not in eval code. start as non-deletable but writable. But runtimes for secure subsets of ES, like ADSafe and Caja, need to be able to freeze the global object of their frame during their initialization. If not for legacy, we could make new properties of the global object start as configurable. Except that deoptimizes all high performance JS engines. If deletable and configurable were distinct, we could make new properties of the global object start as configurable but not deletable. Saving perf but to what end? Does the Caja, etc. programming model require configurability before freezing for all global props, or a few, or one? However, adding another attribute to deal with this one problematic case seemed overkill. Allowing non-configurable properties to be made non-writable seems like the simplest adequate solution. Not arguing, just recapitulating and asking for the Caja use-case. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Sep 3, 2008, at 11:15 PM, David-Sarah Hopwood wrote: In the absence of decimal, Object.eq is trivial to spec: Object.eq(NaN, NaN) = true Object.eq( 0, -0) = false Object.eq( -0, 0) = false Object.eq( x, y) = (x === y), otherwise. or to implement: Object.eq = function (x, y) { if (x === y) { return x !== 0 || 1/x === 1/y; } else { return x !== x y !== y; } }; Even shorter, without else after return non-sequitur and with one guaranteed same-type == instead of === to be perverse: Object.eq = function (x, y) { return (x === y) ? x !== 0 || 1/x == 1/y : x !== x y !== y; } But what's the point? My point was that Decimal doesn't make the case particularly strong, since you just need to add Decimal.compareTotal: Object.eq = function (x, y) { if (x instanceof Decimal y instanceof Decimal) return Decimal.compareTotal(x, y) == 0; return (x === y) ? x !== 0 || 1/x == 1/y : x !== x y !== y; } How much less trivial is this? Two lines, fewer with more ?: chaining. Just not particularly on account of Decimal, even with equated cohort members. If there is a possibility that we are ever going to add decimal (or other types for which === might not be an identity test), then adding Object.eq now allows writing future-proof code for such things as memoizers -- whatever the semantics of === for decimals (or between decimals and other numbers) turns out to be. JS developers have to cope with downrev browsers. There's no imperative now (ES3.1) vs. next time, since they'll need something like the above as fallback for last time (ES3-based) browsers. Again my point is to avoid mission creep in 3.1. I have no problem with identical and hashcode. If I'm wrong and they can be slipped in without any delay, filling inevitable latency in the current schedule, great. I should get busy on the spec. Ob. Bikeshed: You seem committed to eq as the name. I say it's undue Lisp nostalgia, if not arrant cybercrud. But I concede that identical is overlong. Alternative ideas? /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Es-discuss - several decimal discussions
On Sep 4, 2008, at 12:29 AM, David-Sarah Hopwood wrote: 1. You can't do that in ES3.1 if Decimal is not in ES3.1. You'd have to add typeof Decimal !== 'undefined' to the 'if' condition. And then you'd be trying to anticipate a future spec, rather than relying on an existing one. Straw man -- Ajax library authors have to object-detect, they do it as needed. We can't predict the future, so why worry? The point is that Object.eq could be done now or later. There's no imperative to do it now, with or without Decimal. Whatever the mix of Decimal and Object.eq, library authors can and must cope -- since they'll face downrev browsers. 2. This only accounts for Decimal, not for any other future types where === might not be an identity comparison. Accounting for the future is not a reason to add an API that can be self-hosted (and will be, for older browsers). 3. It's not clear to me that this code is correct; at least not without making assumptions about how === will work on mixed arguments that have not yet been agreed. Will 1 === 1m be true (when decimals are added)? If so, then Object.eq(1, 1m) as implemented above will be true when it should be false. We haven't agreed on X, Y depends on X, therefore Y is not ready to spec -- yup, you're right. That doesn't mean we must add Object.eq now just to future-proof (even within the future that's before 3.1 is done!). Cart Horse, ahead of. The size of the code is irrelevant. Object.eq doesn't add significantly to language complexity, and provides a useful basic operation, so why shouldn't it be in the spec? Are you familiar with requirements management, scheduling? It was not the last addition that made us late. It was not the last cookie I ate that made me fat. Unless they are targetting only ES3.1-and-above. At some point (maybe several years) in the future, they'll be able to do that -- provided that Object.eq was added in ES3.1. Or we do it next time and use the self-hosted version in the mean time. You are trying to construct an absolute argument on relative terms. I could do that to add a large number of good APIs to 3.1 but then we'd be done in 2011. But if we keep arguing, we'll miss the chance to fix what's wrong in the current draft spec, so I'm going to stop here -- have the last word if you like. Not really, but eq has been used to refer to this operation for decades in both the Lisp and capability communities. I can live with Object.identical, but I'll always think of it as 'eq'. Ok. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Call for opinions: attribute defaults and renaming flexible
On Sep 5, 2008, at 4:33 PM, Ingvar von Schoultz wrote: Ingvar von Schoultz skrev: Mark S. Miller skrev: On Fri, Sep 5, 2008 at 2:33 PM, Ingvar von Schoultz [EMAIL PROTECTED] wrote: and silent failures are often very expensive to debug. I don't understand. As currently proposed, Object.freeze always succeeds. What silent failure are you concerned about? If you set a property to non-configurable it means you don't want it reconfigured. If code is still allowed to change it from writable to non-writable, this is a silent failure of the guard against reconfiguring. Another silent failure, much more expensive, is when you try to write to non-writable properties. (And, apart from this, also the related similar problem with constant variables). This goes back to ES1. In Netscape's original JS implementation, I reported an error which stopped the script on assignment to read-only properties (this from memory, I don't have source code for the old Mocha runtime). Without try/catch in ES1, this was viewed as too harsh by the TG1 group in TC39, leaving only silent-but-deadly failure to modify the lvalue (the result of the assignment expression is the unfiltered right-hand-side value, so you can't tell). This was not revisited when exception handling was added in ES3 :-(. I would really like to know the reason for this strange problem with non-writable properties, and try to see if there's any way a better solution can be found than this seriously expensive language bug. The proposed solution for ES3.1 and beyond is use strict. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Ye olde arguments argument (was: Topic list - pending changes and issues for the ES3.1 spec)
On Sep 9, 2008, at 1:49 PM, Garrett Smith wrote: On Tue, Sep 9, 2008 at 11:32 AM, Mark S. Miller [EMAIL PROTECTED] wrote: Should strict 'arguments' be an array? I know we've over this before and that strong reasons were presented why we couldn't do this. But on the ES3.1 phone call this morning no one could remember or regenerate those reasons. Anyone? Pointers to previous threads are a fine answer. There was a narrow-cast thread among ES3.1 principals, I replied without enlarging it. Here's my last message in full, citing Allen's agreement: I only now noticed that this mail spun off from a narrowcast mail from Pratap, but the topic (arguments' type) deserves a wider list. [EMAIL PROTECTED] is fine. May be that we are done with this thread, but if not (or if it comes back to life), it should not be too narrowly distributed. There's always the TC39 reflector for member-only stuff. /be On Aug 1, 2008, at 6:26 PM, Allen Wirfs-Brock wrote: OK, I generally buy this, that arguments is an Object but its [[prototype]] is Array.prototype. What about the semantics of its length property and other array specific semantics defined in Array instances’ custom [[Put]] method ([[ThrowablePut]] in the ES3.1 spec.). I would think--yes, which means we will need to define a custom [[ThrowablePut]] for argument objects. That is probably also the appropriate place for defining the mapping to/from actual parameters semantics. At least one thing in Array.prototype that doesn’t fit if arguments is an Object and not an Array. That is the definition of constructor in Array.prototype. We can fix that by explicitly providing an over-riding constructor property on arguments instances. Are there any other properties of Array.prototype that need special consideration? Finally, this brings to mind a subtlety to think about. The Object meta functions can expose whether or not a property is an own property or an inherited property. When the speciation says (as it does in several places) that an instance of a specific constructor has certain properties are we implying that those properties must be observably own properties of the instance? From an implementation flexibility perspective I’d prefer that this was left unspecified but from an interoperability perspective I suppose we should pin it down. From: Brendan Eich [mailto:[EMAIL PROTECTED] Sent: Tuesday, July 29, 2008 7:34 AM To: Pratap Lakshman (VJ#SDK) Cc: [EMAIL PROTECTED]; Mark S. Miller; Kris Zyp; Mike Cowlishaw; Adam Peller; Sam Ruby; Lars Hansen; [EMAIL PROTECTED]; Allen Wirfs- Brock; Waldemar Horwat Subject: Re: ES3.1 WG phone conference 29 July 08:00 PT On Jul 29, 2008, at 7:04 AM, Pratap Lakshman (VJ#SDK) wrote: (3) arguments. I think we should make arguments a true ES array. We should correct the specification error that allowed it to be anything else. This is not possible without extra magic, due to the aliasing of arguments[0] and x in function f(x){arguments[0] = 42; return x} It goes both ways of course: function f(x){x = 42; return arguments[0]} You can't require analysis to find the mutation (of either alias), due to eval. We shouldn't require any kind of analysis in ES3.1 to handle this aliasing. It has to be done as it has always been done, by a magic arguments object whose element getters know how to find the actual parameters, and whose element setters update those actuals that correspond to declared formal parameters. Note that the last sentence requires the first call to f below to return undefined, not 42: js function f(a,b){arguments[1]=42;return b} js f(1) js f(1,2) 42 For these reasons, arguments cannot be a true array. Such a change is also not backward compatible in ways I recall Lars found out about when he was at Opera. The only harmonized solution is to make arguments' prototype be Array.prototype. Let's please do that, or else leave arguments alone. (4) Edits based on review feedback from Oslo; schedule for circulating the next draft Sorry if I cannot attend this meeting -- I will try if my schedule permits. I'm still traveling and I haven't had a chance to dig into chapter 15 of the spec. I hope the above is clear. /be Back to the present: Thanks. There are other threads covering arguments, not hard to find with site:mail.mozilla.org or nabble.com (although both have odd gaps in message indexing -- I'll talk to mail.mozilla.org admins). The arguments object could have the same methods as array, like a subclass of array, but not have the special [[Put]], and concat() could still work the way it does with today's arguments object (I don't actually prefer the current behavior) The plan has been to make arguments objects delegate to Array.prototype. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Function.prototype.bind
On Sep 9, 2008, at 9:47 PM, David-Sarah Hopwood wrote: As an alternative to saying the original bindings of... in the spec, we could provide a way to actually get the original bindings in ECMAScript code. This is independently useful, e.g. for secure subset run-times. Have you read http://wiki.ecmascript.org/doku.php? id=strawman:lexical_scope yet? The Harmony reference implementation work is very likely to cut back the old ES4 RI to ES3 and go forward from there. To avoid hijacking built-in behavior it needs something like the use lexical scope pragma. I have also assumed the existence of a static Function.apply which takes the function to be applied as an explicit first argument. This was part of ES4 and it's in JS1.7+ in Firefox. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Function.prototype.bind
On Sep 10, 2008, at 6:24 PM, David-Sarah Hopwood wrote: David-Sarah Hopwood wrote: Mark S. Miller wrote: On Wed, Sep 10, 2008 at 12:49 AM, Brendan Eich [EMAIL PROTECTED] wrote: I'm willing to rename Function.apply, but let's talk some more about the better name, and about why it matters. Actually now that I think about it, there is an easy fix: Function.apply = original Function.prototype.apply; Then use Function.apply.call(callable, thisobj, argsarray). I should have said that this is assuming the adoption of my other proposal in which static methods of Function (for example) are non-Writable and non-Configurable. Oh, I thought you were dodging the overwrite issue. But your proposal is wildly incompatible and no browser implementor involved in TC39 will ship it (I predict, and aver on behalf of Mozilla, having tried once for all standard constructors). So where does that leave us? /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Ye olde arguments argument (was: Topic list - pending changes and issues for the ES3.1 spec)
Great -- good to have library authors / maintainers on this list. I hold no brief for callee. The only issue in its favor is the cost of migrating to strict mode. A new version of Prototype that loses internal arguments.callee uses and is otherwise compatible helps. Dojo and other Ajax folks on the list, please pipe up. / be Sent from my iPhone On Sep 12, 2008, at 6:54 PM, Tobie Langel [EMAIL PROTECTED] wrote: On Sep 11, 2008, at 14:34 , Brendan Eich wrote: I snipped your words about callee, but it's used quite a bit in Ajax libraries, e.g, Prototype: $ grep -w callee prottype.js replacement = arguments.callee.prepareReplacement(replacement); var self = arguments.callee; parts.add = arguments.callee.addPair; (Prototype 1.5.1.1.) In Prototype, arguments.callee is used in two distinct cases: 1) reading a property of the callee, and 2) recursively calling the callee. Case #1 is easily solved by storing the said property in a closure, or by setting it elsewhere (where it probably would be a better fit, anyway). Case #2 is easily solved by using a named function instead. For the particular case where it is used in Prototype, the anonymous function lies inside of a closure, so there is no chance of triggering the JScript scope bug nor of polluting the global namespace when naming it. From what I understand, ES 3.1 strict mode compliance will be opt-in and will require at least slight source code modifications (if only to prepend it with the 'use strict'; expression). So current versions of Prototype (or other libs, for that matter), will not be ES 3.1 'strict' compliant by default. I'm not really worried about modifying Prototype to avoid use of the arguments.callee property. As a matter of fact, we've already done so in a development branch for Caja compliance. Note that jQuery does not use arguments.callee at all. Best, Tobie ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Regexp capturing groups.
Good point -- could you please file a separate ticket and cite it here in reply? Thanks, /be On Sep 15, 2008, at 7:51 PM, Markus Jarderot wrote: Brendan Eich wrote: Steven did file http://bugs.ecmascript.org/ticket/376 I'll champion fixing this, somehow, in Harmony. We should get Waldemar's opinion on it. /be #376 seems to only concern the issue of back-references to non-participating capture-groups. What I described was back-references to capture-groups within a repetition. As the algorithm in the ECMA-262v3 is currently written, any captures from the last iteration should be discarded. #376 mentions it, but also says that this deserves a separate ticket. I have not found any ticket on this specific issue. I have recently found that also Google Chrome keeps the captures between iterations. URI: javascript:alert(/(?:(a)|(b))*/.exec(ababa)) Firefox 3.0.1: ababa,a, -- no b Internet Explorer 7.0.5730.11 and Google Chrome 0.2.149.29: ababa,a,b -- b in the end -- Markus Jarderot ___ 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: Ye olde arguments argument (was: Topic list - pending changes and issues for the ES3.1 spec)
On Sep 15, 2008, at 10:13 PM, Jorge Chamorro wrote: El 15/09/2008, a las 22:32, Jon Zeppieri escribió: IOW, could we have instead a ('standalone') 'callee' property (that isn't to be innocently passed on) ? ...as a property of what? The activation object of the execution context. I've been there, done that. Long ago, when crazy Smalltalk-ish reflection of execution state was in vogue, SpiderMonkey grew magic reflective properties (ugly names, such as __caller__). The compiler would make functions enclosing such things always have an activation object (real implementations must optimize away activation objects for performance -- there's no other way). Besides violating Tennent's Correspondence Principle, this was an evil mess to implement correctly (consider all the optimizations that had to be undone). It's not worth it, especially if you want just callee (use a named function expression, or bind an outer lexical name) or caller (stack inspection should be served by a carefully designed API on the side -- mirror reflection, not an API on activation objects). I agree with Mark about callee. Just say no, if we can wean folks off of it. Stack backtracing deserves a separate thread. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Ye olde arguments argument (was: Topic list - pending changes and issues for the ES3.1 spec)
On Sep 15, 2008, at 10:21 PM, Jon Zeppieri wrote: Don't even get me started on activation 'objects'... Nor me. Mark, didn't you propose eliminating that language from the spec? (Yup. https://mail.mozilla.org/pipermail/es-discuss/2008-April/ 006062.html) I'm guessing that's not actually happening for ES3.1. May be too big a change for 3.1, on the agenda for Harmony. As Dave Herman has argued, mapping scopes onto objects is a primal sin in the ES specs. Recasting where possible via lexical bindings, putting the global object, with, and eval into penalty boxes, both in real terms for programmers (e.g. use lexical scope), and in the spec by making the bad cases entail exceptional work, seems more than worth the trouble. It's easy to keep hacking around with objects, maybe trying to freeze some bindings, but doing so is a temporary evil at best, or foolish child's-play at worst (if done out of some misguided uber- minimalism, to avoid reforming the spec language to use lexical scope normatively). Guy Steele was editor during much of the ES1 period, and he helped greatly, but compatibility concerns and time-to-market prevented us from taking his advice on this point. I wish we had, though. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Ye olde arguments argument (was: Topic list - pending changes and issues for the ES3.1 spec)
On Sep 16, 2008, at 12:21 AM, liorean wrote: 2008/9/16 William Edney [EMAIL PROTECTED]: Could I do an assignment of the handler? Sure, but syntactically suboptimal, IMHO. Once JScript has fixed the function name scope bug, you could use myElem.addEventListener( 'click', function f(){ doSomething(); this.removeEventListener( 'click', f, false);}, false); Or to work around the JScript bug: (function () { function f(){ doSomething(); this.removeEventListener('click', f, false); } myElem.addEventListener('click', f, false); })(); Lots of workarounds, none free, but still possibly tolerable or even not measurable in performance and memory costs. In case anyone missed it, http://wiki.ecmascript.org/doku.php?id=proposals:stack_inspection Ignore the type parameter and annotations, to see the essential proposal. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: use decimal
On Sep 17, 2008, at 10:13 PM, Mark S. Miller wrote: On Wed, Sep 17, 2008 at 6:50 PM, Maciej Stachowiak [EMAIL PROTECTED] wrote: I agree that typeof 1.5m == typeof 1.1m. However, I do not agree that 1.1m == 1.1. These should be !=, since they represent distinct real numbers. It seems to me that Brendan said 1.1m != 1.1 and did not question this. Brendan, please correct me if I misrepresent your argument. I took Brendan to be saying that 1) If typeof 1.1m were 'number' then we'd be obligated to have 1.1m == 1.1. 2) We want 1.1m != 1.1. 3) Therefore, typeof 1.1m must not be 'number'. I disagree with #1 and thus #3. Here is what I wrote: Without use decimal, typeof 1.1m must not be number to preserve this same invariant [that a === b = typeof a == typeof b a == b]. Otherwise (without use decimal) 1.5m == 1.5 but 1.1m != 1.1, so without making typeof 1.5m != typeof 1.1m, we cannot have typeof 1.5m == number. Please expand your syllogistic reasoning: Major premise #1: a == b Minor premise #1: typeof a == typeof b Conclusion #1: a === b (you can switch == and === above -- the implication goes both ways and choice of == or === for typeof a OP typeof b does not matter since typeof's result is of string type.) Major premise #2: 1.5m == 1.5 Minor premise #2: typeof 1.5m == number (your position, IIUC) Conclusion #2: 1.5m === 1.5 (by Conclusion #1 and ES1-3 (which define typeof 1.5 == number)) Counter-example: 1.1m != 1.1 but typeof 1.1m == typeof 1.1 in your proposal (again IIUC) This is a for-all problem. If there exists some double value x such that, for the decimal form y spelled literally using the same digits but with an 'm' suffix, x != y, yet typeof x == typeof y, then typeof must depend on whether its operand value converts losslessly to decimal from double and double from decimal. This is broken -- typeof should depend on type, not value. Hence my position (Waldemar's too) that typeof 1.1m == typeof 1.5m typeof 1.1m == decimal. However, with the introduction of decimal, we've got cohorts galore. 1.1m has a different operational behavior than 1.1000m, but we've agree they should be ===. With the introduction of decimal, === no longer approximates a test of operational equivalence, and we still need such a test. === does approximate operational equivalence apart from significance. Right? (I'm asking because I could be wrong, not rhetorically!) 0/-0 != 0/0. Does it thus seem wrong that -0 === 0? Well, yes, actually it does seem wrong to me, but we all accept that particular wrongness. This is just more of the same. A lot more. Two wrongs don't make a right. One exception to the rule is better than two, or 2^53 or larger. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: use decimal
On Sep 17, 2008, at 7:48 PM, Sam Ruby wrote: Anybody care to mark up what they would like to see the following look like? http://intertwingly.net/stories/2008/09/12/estest.html Shipt it! (Not in ES3.1, certainly in Firefox 3.1 if we can... :-) /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Decimal comparisons
On Sep 18, 2008, at 10:58 PM, Kris Zyp wrote: * Like Crock, I prefer that typeof 1m === 'number'. However, unlike Crock's and Brendan's agreement, I think this should be unconditional. I think it would be horrible for 'typeof X' to depend not only on the value of X but also on the mode of the program unit in which the typeof appears. Please don't do that. +1 for typeof 1m === 'number'. As an example of breakage, I believe Crockford's current version of his JSON library would not do as I would desire with decimals: JSON.stringify({foo:1m}) - {\foo\:undefined} Why is that worse than producing '{foo:1}'? Consider 1.1m instead of 1m. JSON does not provide for decimal, and receiver-makes-it-wrong is a bug. JSON would need to be extended to handle decimal reliably. I think there is a may be a lot of code that is dependent on typeof returning a one of exactly six possible values. There may be a lot. There's probably some. But there's also probably some code that breaks if decimals are added and they have number typeof-type. There is no non-breaking way to add decimal. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Decimal comparisons
On Sep 19, 2008, at 8:45 AM, Sam Ruby wrote: The motivation for the fourth choice on the first question is to produce a value that is is valid JSON, is unlikely to be widely used today (by virtue of the capital E), will fall back to binary 64 many JSON implementations, and can be used as a signal to produce a decimal value in ECMAScript. I'm merely putting this forward as brainstorming at this point, I'm less than enthusiastic about it myself. http://www.ietf.org/rfc/rfc4627.txt underspecifies enough to allow this kind of trick, but it is possible that the de-facto JSON standard requires IEEE double at the limit. Does the committee feel that it can ever add new values to typeof under any circumstances? Certainly not if there is opt-in version selection. Even with the default version, people on this list have argued that adding a new typeof-type does the least harm and probably could be pulled off, because most typeof-using code does not test type-code values exhaustively. But it's an open question. FWIW, my preference is (in order): decimal, object, then number. I'm with you there. The neo-Platonist camp (:-P) argues for number based on Real numbers, but machines and ES numbers do not behave like Reals. I don't believe object is thinkable without !0m = false, or widely distributed code will fail on decimal values. I think it is preposterous to assume that ECMAScript can never add any new data types. Agreed. The version of JSON that is included in the language will be aware of the data types supported in that edition of ECMAScript. What json2.js does for decimal, it does for any object data type that it doesn't understand. This is not so clear. JSON is a cross-language, inter-networked data standard. It won't be easy to grow in parallel to ES standards. It shouldn't grow without versioning, which I'm sure Doug agrees should be avoided at all costs. The risk for JSON is that because it underspecifies, real-world uses bind to specific implementations details such as number being double. As far as what the builtin JSON functionality slated for ECMAScript 3.1 does when parsing [1.1], a case could be made that producing [1.1m] is the closest to the expressing what the data structure actually conveys, is readily convertible to binary 64 floating point when needed, and typical JSON isn't anywhere near as performance critical as vector graphic intensive functions are. Yeah, you're right that this case could be made from the RFC, although the RFC talks only about range restrictions, not radix or rounding. But from an interoperating JSON peer today, you might find failures to round-trip. That seems bad. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Regexp capturing groups.
On Sep 22, 2008, at 4:17 PM, Waldemar Horwat wrote: Brendan Eich wrote: On Sep 22, 2008, at 3:32 PM, Waldemar Horwat wrote: Brendan Eich wrote: Good point -- could you please file a separate ticket and cite it here in reply? Thanks, I filed a ticket to fix this bug in Chrome. The ticket I was asking for, which Markus is going to file now that he has access to the http://bugs.ecmascript.org/ trac, is against ECMA-262. Are you asking for Chrome (V8, I mean) to deviate from ES3 in order to find out what breaks? If so, great, but how about coordination among Mozilla, Chrome, and WebKit (SFX)? /be No; it's the opposite. I'm asking Chrome to conform to ES3. Could you cite the chromium issue link? I'd like to learn what, if any, web compatibility knowledge was gained in in this case, or could still be gained. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES3.1 Draft: 22 Sep 2008 Redmond version available
On Sep 23, 2008, at 1:45 PM, Waldemar Horwat wrote: Sam Ruby wrote: One minor request: statements like breaks arrays are less helpful than specific ECMAScript statements which would fail; better yet would be citing specific deployed code that would fail. I already gave specific examples of this and we've had extensive discussions of them. I don't like beating a dead horse any more than necessary. The horse must not be dead. The question is: should a === b imply o [a] and o[b] refer to the same property, for any object o (modulo the spec bug that David Jones pointed out whereby 5e-324 could be converted to strings such as 3e-324 and 7e-324). Sam seems to think a === b should not imply o[a] and o[b] refer to the same property (double-cited text is from Jason Orendorff): Well, the intuition is that two equal numbers should index the same property. This is an invariant in ES3 and it makes a lot of sense. Correct me if I'm wrong, but the intuition would more properly be based on string equality, and not numeric equality. As an example, how many properties would the following produce, with an conformant implementation of ES3? var a = []; a['0.0'] = first; a[0.0] = second; // a second property a['0'] = third; // replaces *second* property The intuition depends on string equality and ToString in addition to numeric equality. But it turns out that a === b for any numbers a and b implies ToString(a) === ToString(b) (except, again, for the very small numbers David Jones pointed out). But Sam's decimal implementation has 1.1m === 1.10m. So the precise issue with breaks arrays is the proposal from Sam and Mike that ToString on a decimal preserve scale digits (I hope I'm using the right term). That breaks the a === b = o[a] is o[b] rule that exists today (modulo tiny values) for numbers a and b, when extended to decimals a and b. Intuition is a very tricky thing. Place the following in front of any third grader, and tell me what they will write below the line. 1 . 0 5 + 2 . 0 5 _ Of course the result should be 3.10 on paper, but this does not say that ToString applied to decimal must preserve scale digits. One alternative is to distinguish the operation used when computing a property name from the ToString used everywhere else, and make the former lose scale digits while the latter preserves them. There's no doubt a 754r method for converting to string without trailing zeroes or otherwise preserving scale (those funny exponents Waldemar decried). If we did this, we would have to complicate the spec by adding a special case to its computed property name logic. And users wishing to mimick it with explicit conversion to a string would not be able to use String(d) or + d -- they would have to call the other method. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Decimal status
On Sep 24, 2008, at 9:01 AM, Mike Cowlishaw wrote: I'm not sure what you are getting at. a[1] and a[1.000] refer to the same property in ECMAScript, but a[1m] and a[1.000m] would not. Are you saying this isn't a problem? Absolutely not a problem ... many languages (and ES itself) which index 'arrays' by strings treat the index 1.000 as different from 1, and this is not considered a problem. But they do not treat 1.000 as an index differently from 1. Explicit string indexes, whether literally expressed or computed, are not the issue here. This is, no doubt, because if one is treating array indexes as a set of integers you use integer operations on those indexes (almost exclusively +, -, and *). If one does use a divide, Maciej pointed out reciprocal multiplication as strength-reduced division; this is done often enough in graphics and other low-level code. it would be carefully chosen to produce an integer result; But what if scale is preserved? anything which produced a result without an exponent of 0 would always be more likely to give a non-zero fraction that .0, .00, .000, etc. -- and those non-zero ones would fail rapidly. Sorry, I didn't follow this (that should be than?). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Decimal status
On Sep 24, 2008, at 9:18 AM, Sam Ruby wrote: [over-top-citing trimmed] The concern remains, though. Not due to power-of-five problems that would lead to 0.09987 or the like, but from cases where a number was spelled with extra trailing zeros (in external data, e.g. a spreadsheet) but fits in an integer, or otherwise can be expressed exactly using powers of two. The burden of proof here is on the invariant breaker :-/. I fully appreciate the need for a high bar here. Sure, so maybe that bar height is why people talk about broken. It's a presumption of guilt, alien to Anglo-Saxon jurisprudence. The Napoleonic ECMAScript code prevails here. Beware! :-P. The problem here is that there are two invariants. === to a high degree of accuracy today is an eq operator. But people have argued against 1.2 !== 1.20, because of another invariant: a == b typeof(a) === typeof(b) implies a === b We can't satisfy both. I do not think === is eq -- it's hard to argue degree when kind is the issue, as others have pointed out. Any hashcode addition would want eq, or force people to invent it at tedious and ineffecient length. Past posts here have mixed up cohort and -0 vs. 0, but we've been educated thanks to MFC. Really, === breaks down on NaN and the zeroes, and there's no way to rationalize it as eq. I noted how Guy Steele helped us get past one broken equality operator, in order to add === and !== in ES1, and we talked about eq then. It still looms in the future, Harmony or (some argue) 3.1. My initial preference was that 1.2 !== 1.20, but as we are not aware of code that uses fractional indexes, but are aware of code that does generic typeof and equality testing, I would think that the latter would have a higher weight. Ignoring === as faux eq, the only issue here is d.toString() for decimal d: should it preserve scale and stringify trailing zeroes and funny exponents? /be /be - Sam Ruby ___ 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: Arguments and formal parameters aliasing
On Sep 27, 2008, at 8:14 PM, David-Sarah Hopwood wrote: liorean wrote: [...] 10.1.3 Variable Instantiation [...] If two or more formal parameters share the same name, hence the same property, the corresponding property is given the value that was supplied for the last parameter with this name. Can anyone explain what the original rationale was for this? To me it seems like duplicate parameter names are an obvious programming error, and it makes no sense from a language design point of view to allow them. I do not know. Shon Katzenberger of Microsoft may be the only person who can say. Duplicate formals were not allowed in my original (Mocha) Netscape 2-3 and rewritten (SpiderMonkey) Netscape 4-era implementations. JScript allowed them and the standard included them as a compromise (there were compromises in the other direction). (Yes, I understand that they are disallowed in ES3.1 strict mode, and that disallowing them in non-strict mode would break compatibility. I'm just curious what was going through the minds of the ES1 standardizers.) The rationale is lost to the mists of time. I vaguely recall some belief that looseness in other parts of the language justified allowing duplicate formals, but bad doesn't justify worse. The complexity involved in supporting duplicate formals (compiling and decompiling) is out of proportion to any subjective value in the feature. Really, it's just a botch hammered out during ES1 standardization based on JScript. There were botches on the JavaScript (Netscape) side too, so I'm not throwing stones. Anyway, soon we can just use strict and move on. :-) /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Sep 2, 2008, at 2:16 PM, Lex Spoon wrote: On Sun, Aug 24, 2008 at 3:17 AM, Brendan Eich [EMAIL PROTECTED] wrote: First, let's settle the hash over whether any desugaring without extensions such as return-to-label, reformed lexical scope, tamed this, banished arguments, etc. etc., trumps adding a new binding form, to wit: let as block scoped var. With no extensions, it is true, return would end up returning from a different method under the proposed rewrite. Likewise, this and arguments would cause trouble. Sorry for the very tardy reply. You make good points in the abstract, and the messy language-specific details of existing semantics for functions not being clean enough deserves a better response than just don't desugar. I stand by don't desugar let to functions as-is. I'm also pretty certain don't add more modes or subsets to try to fix existing forms is sound, since versionitis does not help us either keep the spec simple or specify the backward-compatible semantics in the full language. So, to avoid trouble, we've been thinking of new forms including a better function, call it lambda, that has none of the compatibility baggage. I say we but really Dave Herman deserves credit for championing this. A lambda form has been a topic now and then for a while, on this list and in committee, and sometimes only as syntactic sugar (which would miss the opportunity for semantic reform) -- yet without it getting the breathing room it needs. Dave is working now in the http://wiki.ecmascript.org/doku.php?id=strawman:strawman space on the wiki. Don't throw stones, this is not in the harmony: namespace for good reason. Constructive comments welcome. And I still owe the list a story on wiki access that keeps Ecma happy and doesn't throw open the edit wars doors. Among the new strawman pages, the following are relevant and (I hope) helpful: http://wiki.ecmascript.org/doku.php?id=strawman:lambdas http://wiki.ecmascript.org/doku.php?id=strawman:lexical_scope http://wiki.ecmascript.org/doku.php?id=strawman:return_to_label Possibly break and continue would, depending on what their precise semantics are. JS has break from labeled statement, and continue to labeled loop bottom, a la Java. These look trouble-free to me. Let me know if you see a hard case. Thanks, /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 9, 2008, at 3:05 PM, Lex Spoon wrote: On Thu, Oct 9, 2008 at 5:31 PM, Brendan Eich [EMAIL PROTECTED] wrote: JS has break from labeled statement, and continue to labeled loop bottom, a la Java. These look trouble-free to me. Let me know if you see a hard case. Thanks, My question was whether the semantics of break and continue would support the following: while(true) { (function() { if (--x == 0) break; })(); } That's currently a specified error (possibly at runtime; chapter 16 of ES3 allows it to be at compile time). So a future edition could allow it, probably without opt-in versioning. Our compatibility model does not guarantee exceptions, since it allows contemporaneous extensions that remove those exceptions (see ES3 chapter 16 again, second bulleted list, first bullet -- these lists need their own sub-sections and numbers!). I honestly don't know, but it shouldn't cause any real trouble to allow it. The implementation would be analogous to that for labeled return. Right, and break to label outside the function's body, but lexically in scope, would be completely analogous (or just the same ;-)): L: while (true) { (function () { ... // stuff possibly including a loop or switch that brackets the next line if (--x == 0) break L; ... })(); } For example, if the appropriate while loop is no longer on the stack, the break would turn into an exception. Yes, this new runtime exception is the price of admission. The exception seems to a major source of grief in the Java BGGA closures controversy, or at least it did when I last looked. But it comes up with escape continuations in Scheme, and it is inevitable if we want these kinds of program equivalences. I'm interested in the reactions of others on the list to such return/ break/continue from already-deactivated statement/frame exceptions. They could be caught and handled, of course. Feature and bug, dessert topping and floor wax ;-). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 9, 2008, at 4:28 PM, David Herman wrote: How would people feel about the declaration form being 'define' instead of lambda? As in: define const(x) { lambda(y) x } Maybe I'm just accustomed to Scheme, but it looks awkward to me for the declaration form to be called lambda. Dylan also used 'define'. For named functions, it's less cryptic, it has clearer connotations. For anonymous functions, e.g.: (define (x) {...})(x) or return foo(define (y) {...}, z); your mileage *will* vary, but it seems worse by a hair to me. But I'm used to lambda as a term of art. The obscurity of lambda helps it avoid collisions (we have ways of unreserving keywords in property-name contexts, but these do not work for formal parameters and variables named define, which seem likelier at a guess than lambda -- spidering the web could help confirm this guess). The obscurity also arguably partners lambda better with function. Setting up define as a cleaner function seems to switch domains of discourse. Concretely, we have in ES3.1 Object.defineProperty and similarly named functions. These define APIs were prefigured by Object.prototype._defineGetter__, etc.. This sense of define has meant bind property name to value or getter/setter. On the other side, Python, E, etc. use def. But we would be verbose like Scheme and Dylan. So define vs. lambda. End of my bike-shedding ruminations. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 9, 2008, at 6:44 PM, David Herman wrote: Sorry, I was unclear. No, my fault for missing declaration form. I meant 'lambda' for the expression form and 'define' for the definition form. Do keywords cost more than concepts? If people think define name(x) x and lambda (x) x are different beasts, then different names win. If people think of lambdas (what else to call them? not functions) as being named or not when used as expressions, and named when declarations (parallel to the existing function forms are in ES3), but being different (albeit similar; cleaned-up) function-like beasts, then one name for the three forms that parallel the ES3 function forms seems better. It's hard to argue about from first principles outside of the specifics of ES3 and modern JS implementations and teaching. The specific JS books I know talk about functions having several forms, so it seems better to me to keep lambda parallel. I see the appeal of define for the declaration (definition, rather) form, though. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 9, 2008, at 8:57 PM, Peter Michaux wrote: This keyword/scoping problem must already have appeared for functions as function declarations have var scoping and obtaining let scoping requires using something like let a = function(){}. This is pretty ugly for functions to have let scoping An agreement from TC39 this past sprint was that function definitions directly nested in blocks, not specified by ES3, defined block-local (let) bindings. There was general aversion to 'let function f() ...', an earlier ES4 idea already on the ropes. Separating binding forms from function definition and other options (such as const) avoids too many binding forms ('let const', 'let function', etc.). But too many binding forms is just too many, and the committee strongly favored using grammatical placement to avoid adding more syntactic complexity. but the good news is the door has been left open for real lambdas to snatch up the available var a(){} and let a(){} syntaxes. There's no reason to add var a() {} given function a() {} as a direct child of a program or function body. It seems to me let a(){} is Dave's define. So we're back to function vs. define/lambda. The idea of a desugaring let statement and let expression require lambda, the reformed function (whether define wins or not). But let declarations as the new var do not desugar to lambdas. They hoist, even if forward references (use before set) are errors. We haven't found a reformed var; I don't think there is one. This does not mean let declarations are somehow not worth adding. They're a big improvement on var declarations in our experience with let in JS1.7 and up. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Revenge of the double-curly [Was: return when desugaring to closures]
On Oct 10, 2008, at 5:44 AM, P T Withington wrote: On 2008-10-10, at 02:29EDT, Brendan Eich wrote: An agreement from TC39 this past spring was that function definitions directly nested in blocks, not specified by ES3, defined block-local (let) bindings. Holy smokes. Does that mean we are all going to be writing function ... () {{ ... }} to get 'normal' scoping of function body declarations??? No. My words were unclear, sorry. I wrote defined block-local (let) bindings meaning the functions defined in blocks bound *their own names* only in the containing block, not in the variable object. Will `var` mean `let` in those double-curly bodies? No, var and let mean the same thing at top level. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Revenge of the double-curly [Was: return when desugaring to closures]
On Oct 10, 2008, at 11:58 AM, P T Withington wrote: ? If so, perhaps you can see how I might imagine that: function foo () {{ var bar = ...; }} might be sugar for: function foo () { let bar = ...; } Nope, not compatible and not what I meant. Just the function's name is let-bound (block-scoped) for a function defined directly in a block. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 10, 2008, at 1:25 PM, Waldemar Horwat wrote: So what should f(5, 0) do? function f(x, h) { while (true) { try { if (h == 0) h = function() {break}; Just to repeat something Dave wrote, we don't propose to allow break in a function where the break is not in a labeled statement, switch, or loop within that function. Only lambda would support such novelties. if (x != 0) f(x-1, h); else h(); This will break from the while (true) in the outermost (x = 5) activation of f. In Scheme implementations that support it, the analogue is call/ec -- call-with-escape-continuation (weak continuation is another name for escape continuation) -- where the caller's continuation is the argument to the procedure passed to call/ec. Escape continuations are cheaper to implement and simpler to reason about than full call/cc continuations because of the dynamic error (exception) you get if you call the escape continuation outside of the dynamic extent of the current call. Sorry if this is already known; Dave should wipe my chin as needed since he is the adult Schemer here and I'm the toddler. } catch (e) { alert(caught + e + on + x); } finally { alert(f called finally on + x); } alert(f looping on + x); } alert(f exited on + x); } The break itself does not propagate as an exception, just to be clear. If the statement being broken from is inactive, then an exception will be thrown from the break evaluation in the function that was assigned to h. The call to h would have to come after control flow had left the outermost while (true), via a statement after that loop, or some other call made via a returned or heap reference (upward funarg). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 10, 2008, at 3:31 PM, Brendan Eich wrote: } catch (e) { alert(caught + e + on + x); } finally { alert(f called finally on + x); } Skipping the intervening active finally clauses is bad, though -- a bug in the current wiki rough draft that I should have mentioned. Dave will post a follow-up soon. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Revenge of the double-curly [Was: return when desugaring to closures]
On Oct 11, 2008, at 7:25 AM, David-Sarah Hopwood wrote: It is correct to say, though, that: function foo() { ... { var bar = baz; } ... } is equivalent to function foo() { let bar = undefined; ... { bar = baz; } ... } That is, 'var' need not be primitive. Only 'let' needs to be primitive. Indeed. Similarly, if we are careful in specifying 'lambda' then 'function' need not be primitive, since it will be expressible as a rewrite to 'lambda'. Yes, this is called out already in http://wiki.ecmascript.org/doku.php?id=strawman:lambdas /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 11, 2008, at 12:55 PM, David Herman wrote: How to define a variable that is local to the enclosing lambda? Isn't the ability to do that essential? No. With all due respect to Brendan, `var' hoisting to the top of a function body is one of the more problematic aspects of ES's semantics. I agree, it's no skin off my nose -- 'var' hoisting was an artifact of function implementation in Netscape 2, and did not apply to global vars then. It was standardized as hoisting in all kinds of code (global, function, and eval). We are stuck with it. However, hoisting still applies to let: If you want a local variable, use `let' -- it'll be local to its containing block. If you want a variable that is local to the entire body of a `lambda', use `let' at the top level of the `lambda' body. While let is local to containing block, the let-as-new-var proposal (implemented in Firefox 2 and up) hoists to top of block. So you cannot initialize the inner x using the outer x's value: { let x = 42; { let x = x; // undefined, not 42. alert(x); } alert(x); // 42, of course } We've discussed making use-before-set a strict error, but we've avoided it. The initialiser is not mandatory, and we do not wish to impose costly analysis on small implementations. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 11, 2008, at 12:52 PM, Peter Michaux wrote: On Sat, Oct 11, 2008 at 11:59 AM, Brendan Eich [EMAIL PROTECTED] wrote: On Oct 11, 2008, at 9:05 AM, Peter Michaux wrote: How to define a variable that is local to the enclosing lambda? Isn't the ability to do that essential? Use let (the var replacement declaration form). Sounds good to me but it is a little confusing to keep track if let is either in or out of ES-Harmony I do not see why you are confused. I wrote, in the original ECMAScript Harmony post: I heard good agreement on low-hanging de-facto standard fruit, particularly let as the new var, to match block-scoped const as still proposed (IIRC) in 3.1. See https://mail.mozilla.org/pipermail/es-discuss/2008-August/006837.html . and if it is partly in then which of the several JavaScript 1.7 uses are in and if there will be let, let*, letrec semantics. It's something else. See my reply about hoisting, just sent. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 11, 2008, at 2:43 PM, Brendan Eich wrote: On Oct 11, 2008, at 12:52 PM, Peter Michaux wrote: and if it is partly in then which of the several JavaScript 1.7 uses are in and if there will be let, let*, letrec semantics. It's something else. See my reply about hoisting, just sent. Mark and others have described the let declaration (let as new var) as like letrec. Close, but since forward references are possible and initiialization in the declaration is not mandatory, it's analogous, not identical. The function definition form in JS is letrec. But let as new var? I still say it's something else; I admit that like letrec or letrec-ilke works. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 11, 2008, at 2:55 PM, Mark S. Miller wrote: On Sat, Oct 11, 2008 at 2:42 PM, Brendan Eich [EMAIL PROTECTED] wrote: We've discussed making use-before-set a strict error, but we've avoided it. The initialiser is not mandatory, and we do not wish to impose costly analysis on small implementations. Since const use-before-set is an unconditional error (i.e., not dependent on strictness), implementations already have to pay for a read-barrier mechanism. Since we'd like to support type-annotation-constraints on initialized let variables, I think initialized let variables should have an unconditional read barrier as well. If using an uninitialized let binding is an error, then hoisting is pointless except to make the statements between start of block and the let declaration a dead zone for the binding name. This fits the ancient, weak but not entirely worthless post-hoc rationale for var hoisting (to avoid confusion among novice or inexperienced programmers by making many scopes, each implicitly opened by var), but it's not particularly useful. What's more, as discussed here and in TC39, repeated let declarations for the same binding name within the same block should be allowed. Anything else is user- and refactoring-hostile. So the non-initial let declarations for a given name in the same block would be ignored. This leaves efficiency as a concern. If implementations do not do the analysis required to catch use before set at compile time, then let as well as const pays the read barrier price. It's non-trivial. Today let (and var in the absence of eval) can be optimized to use a read in the VM, possibly even a load instruction -- no getter barrier required. Whatever the GC write barrier cost, reads dominate and this is a significant savings. On the other hand, computing SSA including dominance relations while parsing (in one pass) is possible so long as we do not add goto to the language. So maybe the analysis is acceptable to modern implementations, which are increasingly sophisticated. Still, it is not yet agreed that let use before set shall be an error. It certainly is not the case for var, and working code counts on the undefined default initial value. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 8:43 AM, Mark S. Miller wrote: On Mon, Oct 13, 2008 at 8:05 AM, David-Sarah Hopwood [EMAIL PROTECTED] wrote: for (var ...) implicitly introduces a block whether or not it is a substatement. This is a wart of C++/C99/Java syntax that we have to live with, since too much code relies on it. Yes, but how do we live with it? The only currently allowed case, var as above, is no problem, since it hoists to the function body anyway. But what about let. Do we all agree that in for (let x = ...) {...x...} ... x ... the x after the for loop does not refer to the x defined by the for loop? In that case, no problem with for being a SubStatement. No one ever proposed otherwise for for (let...), and it would be nuts to do anything like that. A remaining interesting question is whether the for loop reassigns to a single per-for-loop-entry x, or whether it initializes a fresh per-iteration x. If the for loop body has a closure that captures x, it makes a difference. I recommend the per-iteration view. If we can agree quickly on per-iteration, then for (const x = ...) {...x...} should be allowed in ES3.1 (whether or not const hoists to block start). After ES3.1 for (const i :T[i] = ...) {...; a[i] = function(){...i...}; ...} would then mean what it should mean. Cool. Agreed. See https://bugzilla.mozilla.org/show_bug.cgi?id=449811 -- which is a bug we'd like to fix by following a spec. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 3:51 PM, Waldemar Horwat wrote: Brendan Eich wrote: After some experiments, we decided for ES4 to make let and var the same at top level in a function or global code. This helped avoid implementation pain: very long scripts on the web, consisting of many statements in a row, motivate statement-wise parsing and cumulative code generation, which is straightforward in the absence of goto. Yet scope changes (e.g. due to a tardy rogue let x; after thousands of statements the first of which uses x) require a separate pass to generate the necessary block set-up code before the first use of x. Unifying let and var at top level also reduces the cognitive load (number of scopes in mind) and eliminates useless name shadowing opportunities. But such let/var unification at top level in a function body does leave bad old arguments[0] aliasing x in the above example, allowing mutation of otherwise lexical let x; (change var to let and fill in the ... with arguments[0] = 42; return x). The answer that we chose for ES4, and the one that's already agreeable in committee for Harmony, was deprecate arguments by providing optional and rest parameters. You can't do that. Which that do you mean? function f() { x = 15; ... let t = some_runtime_expression; ... let x:t = ... } What is the type of x at the beginning of the function? The example had better fail to compile. I hope my point about implementations optimizing for very long AST hedge programs on the web is mixed up here. Such implementations build a full AST for function bodies, and function bodies tend to be reasonably short on the web (Tennent be damned). Long global code consisting of repeated assignment statements, OTOH, can suck up too much time and space if compiled as a whole instead of incrementally. But I still don't know which that you meant. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 3:56 PM, Waldemar Horwat wrote: Brendan Eich wrote: The agreement from the May TC39 meeting was that the declarations implicit (:*) and explicit annotations must normalize to the same type, or there's an error. That was back when the language had lots of requirements for compile- time expressions, including on all types. We agreed that that's not part of ES-Harmony, and this condition doesn't make sense when type expressions are evaluated at run time. True enough -- but even without normalization, multiple equivalent (at runtime, depending on flow) annotations could be allowed. Should they be? /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 4:01 PM, Waldemar Horwat wrote: Brendan Eich wrote: If using an uninitialized let binding is an error, then hoisting is pointless except to make the statements between start of block and the let declaration a dead zone for the binding name. This fits the ancient, weak but not entirely worthless post-hoc rationale for var hoisting (to avoid confusion among novice or inexperienced programmers by making many scopes, each implicitly opened by var), but it's not particularly useful. This was our agreement from the ES4 days. It's very useful, in that it allows mutually recursive lambdas. For function bindings, yes, of course -- but we were talking about let bindings (I thought). For let (there is no 'let function') bindings, how? Could you give an example? What's more, as discussed here and in TC39, repeated let declarations for the same binding name within the same block should be allowed. You can't do that in ES-Harmony. There is no way to tell if the two let declarations have the same type. There has to be a way to answer the question are these two terms the same type at run-time. For orthogonality you'd also need to allow multiple const declarations within the same scope, and I just don't want to go there. I don't agree -- const and let are different keywords, they obviously differ in read-only vs. writable binding. They could differ otherwise. Anything else is user- and refactoring-hostile. So the non-initial let declarations for a given name in the same block would be ignored. This is loaded language, but I can't tell how requiring there to be a unique point of definition for a const or let is user-hostile. My words were about let, not const. If let is the new var, then you either accept that re-declaration in the same block (usually function body) of the same name via var is common for good reason, and allow let to be used instead; or you raise the migration tax. I do not mean to over-load the language, but we've seen a lot of code that redeclares using var (e.g. for (var i...) in adjacent for loops). We tried making a strict warning (error console spew) for redeclarations of same kind (var vs. var) four years ago (IIRC -- Firefox 1 betas) and felt the heat from developers. We fell back on mixed var vs. function (const vs. anything is an error of course). People on this list have argued similarly based on refactoring and var hoisting. It may be that the migration tax must rise here, but I'd like to know why type annotations can't be equated at runtime. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 4:14 PM, Jon Zeppieri wrote: Yes, and binding a fresh induction variable on every iteration makes sense for a 'for-each' loop (as in the bug report you cited), where the user is not in charge of updating the induction variable by means of explicit assignment. In a plain 'for' loop, however, it *is* magic if an assignment results in a fresh binding. Why is the assignment operator relevant? The question is the binding scope of i in for (let i = 0; i N; i++) ... No curly braces required, we already have this in JS1.7+ and the let is scoped to the for head except for the initializer of i (you can write let i = x, j = y; too -- x and y are evaluated in the outer scope). There's scope magic in this form even though it uses = for assignment and creates only one block scope for the loop, no how many times the loop iterates. And it's unexpected magic. Users differ on this point, but we've had long-standing confusion and complaints about closures capturing the last value of i in let a = [1,2,3,4]; let b = []; for (let i = 0; i a.length; i++) b[i] = function () { return i*i; } and the like. Getting 16 back from b[0]() is unexpected bad magic. Users may be modeling closures as capturing bindings, not scope chains of mutable objects, one per for (let...) statement or explicitly braced block. If so, could we make let declaration capture this way? Again, I'm proceeding from real users' complaints, not idle wishes. Mark said that there was a desugaring for 'for' to 'lambda,' without special cases, where this all works out, but I haven't been able to figure out what rewrite he had in mind. Tail-recursive lambda rewrite of a C-style for loop should be easy for you :-P. Doing it the way Mark proposes fixes the bug, and has no other bad effects that I can see (but we'll have to implement and user-test to be sure). Turning an assignment into a non-assignment is bad. Assignment is not the issue, the binding's scope is. https://bugzilla.mozilla.org/show_bug.cgi?id=449811 Like I said, it makes sense for 'for-each.' Progress! /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 4:09 PM, Brendan Eich wrote: On Oct 13, 2008, at 4:01 PM, Waldemar Horwat wrote: Brendan Eich wrote: If using an uninitialized let binding is an error, then hoisting is pointless except to make the statements between start of block and the let declaration a dead zone for the binding name. This fits the ancient, weak but not entirely worthless post-hoc rationale for var hoisting (to avoid confusion among novice or inexperienced programmers by making many scopes, each implicitly opened by var), but it's not particularly useful. This was our agreement from the ES4 days. It's very useful, in that it allows mutually recursive lambdas. For function bindings, yes, of course -- but we were talking about let bindings (I thought). For let (there is no 'let function') bindings, how? Could you give an example? Obvious example: { let even = function (n) n == 0 || odd(n - 1); let odd = function (n) n != 0 even(n - 1); print(even(42), odd(42)); print(even(99), odd(99)); } My words about function binding meant to suggest: why not require users to write { function even(n) n == 0 || odd(n - 1); function odd(n) n != 0 even(n - 1); ... } But I'm not arguing that we shouldn't hoist let to top of block, only trying to justify my not particularly useful assertion ;-). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 5:00 PM, Jon Zeppieri wrote: On Mon, Oct 13, 2008 at 7:39 PM, Brendan Eich [EMAIL PROTECTED] wrote: On Oct 13, 2008, at 4:14 PM, Jon Zeppieri wrote: Yes, and binding a fresh induction variable on every iteration makes sense for a 'for-each' loop (as in the bug report you cited), where the user is not in charge of updating the induction variable by means of explicit assignment. In a plain 'for' loop, however, it *is* magic if an assignment results in a fresh binding. Why is the assignment operator relevant? The question is the binding scope of i in for (let i = 0; i N; i++) ... How is scope the issue? As far as I know, we don't disagree about scope. Probably we're at cross purposes (I often am ;-) because of the primal sin in ECMAScript of specifying scope via object, and closure via scope chain capture. The assignment I'm referring to, in this example, is the 'i++' part. Mark is proposing that this does not mean increment i by one, but rather rebind i with the value of i+1 -- which is completely different and not what the user wrote. Gotcha -- I agree, this is a problem for a proposal that tries to desugar for(;;). Curses. The user expectation with a closure in a for(var i = 0; i N; i++) loop, that each closure captures i's current value, remains, completely parallel to the for (i in o) ... case. Any attempt to solve it via let instead of var -- other than by making multiple (blech) scope (barf) objects, one per iteration -- must respecify how closures work. Hmm. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 4:54 PM, Waldemar Horwat wrote: I am talking about let bindings. Lars brought up at that meeting. I did not find the use cases particularly convincing, but the dead zone is compelling. There are four ways to do this: A1. Lexical dead zone. References textually prior to a definition in the same block are an error. A2. Lexical window. References textually prior to a definition in the same block go to outer scope. B1. Temporal dead zone. References temporally prior to a definition in the same block are an error. B2. Temporal window. References temporally prior to a definition in the same block go to outer scope. Let's take a look at an example: let x = outer; function g() {return outer} { g(); function f() { ... x ... g ... g() ... } f(); var t = some_runtime_type; const x:t = inner; function g() { ... x ... } g(); f(); } B2 is bad because then the x inside g would sometimes refer to outer and sometimes to inner. A1 and A2 introduce extra complexity but doesn't solve the problem. You'd need to come up with a value for x to use in the very first call to g(). Furthermore, for A2 whether the window occurred or not would also depend on whether something was a function or not; users would be surprised that x shows through the window inside f but g doesn't. That leaves B1, which matches the semantic model (we need to avoid referencing variables before we know their types and before we know the values of constants). Agreed, this is compelling, it shows the insufficiency of lexical order. I missed this somehow (where are those meeting minutes? Still being vetted by TC39?). Thanks for restating it. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 13, 2008, at 6:08 PM, Waldemar Horwat wrote: Brendan Eich wrote: Because presumably the let x:t became var x:t and var can't have types? Why can't var have a type annotation? Because a function can have many var declarations for the same variable and because you can use the variable before any of the var declarations are evaluated. You can work out the implications easily enough. This has been brought up at meetings before. Of course, ES4 had var x:t all over, but as you noted, different rules for evaluating t. Still, with new syntax comes the opportunity for reformed semantics, including restrictions on any bad var abusages we would like to move away from. So my question remains (amended to be clear about what is the same): why does this mean we cannot equate let and var scope at the top level? I'm not talking about allowing them to mix in bad ways, or mix at all (see below). I'm talking about not having an implicit block around top-level function and global code. You wrote that you'd like let to become var (and unlike let as used within an independent block) if used at the top level of a function: Ok, sorry for being unclear. I do not mean to translate top-level 'let' to 'var' and free let bindings from necessary restrictions. I do mean that let binds in the variable object, and let usage restricts other usage. We can forbid mixed var x and let x at top level. We can require the same single definition for any let x at any level. We can forbid arguments usage if arguments[i] could alias a let binding, since let is new (along with rest and optional parameters to enable arguments deprecation). But must we have an implicit block around programs and function bodies that contain let declarations, distinct from the variable scope (object)? What did you mean by had better fail to compile? Other than the type annotation, there is nothing about function f() { x = 15; ... var t = some_runtime_expression; ... var x:t = ... } that ought to fail to compile. The assignment to x in that temporal dead zone before t's initializer has been evaluated. Why is this different if you s/var x/let x/? /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: For Loop Desugaring (was: return when desugaring to closures)
On Oct 13, 2008, at 7:48 PM, Mark S. Miller wrote: On Mon, Oct 13, 2008 at 5:00 PM, Jon Zeppieri [EMAIL PROTECTED] wrote: 1) for (var i = 0; i len; i++) ... continues to mean what it means in ES3. 2) for (let i = 0; i len; i++) ... has the proper scope for 'i' (which you reiterated above), *and* 'i' is rebound -- not mutated -- on each iteration. 3) The rewrite rules are the *same,* regardless of whether it's a for (var ...) or a for (let ...) loop. At least, that's what I took Mark to mean. He can correct me if I'm wrong. You're right. However, the desugaring is more complex than I expected. Thanks for asking me to write it down. for (keyword varName = initExpr; testExpr; updateExpr) { body } desugars to (hygienic renaming aside): breakTarget: { const loop = lambda(iter = initExpr) { keyword varName = iter; if (! testExpr) { break breakTarget; } continueTarget: { body } lambda(iter2 = varName) { keyword varName = iter2; updateExpr; loop(varName); }(); }; loop(); } I believe this meets all your requirements. Requirement 3 is met because var hoists to the enclosing function. This is the part I missed -- well done. Note that continue; in body translates to break continueTarget; and break; translates to break breakTarget; -- you knew that ;-). However, in contradiction to my original claim, one couldn't usefully say const instead of let with a for(;;) loop. Why not usefully? It's true the consts do not hoist to leave an effect in the variable object, but they do ensure const-ness. The body and update cannot mutate the nearest varName binding. This is sometimes useful and existing const implementations allow for (const...). I do not think it should be rejected just yet. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 14, 2008, at 7:38 AM, Neil Mix wrote: On Oct 13, 2008, at 6:39 PM, Brendan Eich wrote: Users may be modeling closures as capturing bindings, not scope chains of mutable objects, one per for (let...) statement or explicitly braced block. If so, could we make let declaration capture this way? Again, I'm proceeding from real users' complaints, not idle wishes. Are you suggesting that closures over let capture bindings in the general case? I hope not. I think for loops are a special case, otherwise let is not the new var. ;) What about for-in loops? I'm proceeding from user expectations being confounded. Something needs help here, possibly not for (;;) loops -- but almost certainly for-in loops containing closures capturing the loop variable. WRT for loops, it's important to remember that let provides an alternative that wasn't possible with var. Suppose for moment we do *not* rebind on every iteration: for (let i = 0; i objects.length; i++) { let j = i; objects[i].callback = function() { print(j); } } Yes, this is in the bug I cited (https://bugzilla.mozilla.org/show_bug.cgi?id=449811 ). It is still a PITA. The syntactic overhead for such a workaround is much less than for var: for (var i = 0; i objects.length; i++) { objects[i].callback = buildCallback(i); } function buildCallback(i) { print(i); } True, which makes it even more painful in some ways. Why doesn't JS do it for me? Closer, almost-but-not-quite-right, is torturous. The for/closures bug is definitely a newbie trap, but its pain is not its discovery, but the difficulty of working around it. To me this could be a winning argument against re-binding on each loop, since re-binding precludes the (admittedly dubious) use-case of updating inside the body: for (let i = 0; i 100; i++) { if (skipAhead) { i += 9; continue; } ... } So we can have our cake and eat it too with a tail-recursive desugaring that forwards the previous iteration's binding value to the next iteration's binding. Of course any practical implementation will have to do more analysis than is currently done in the top open-source implementations I've looked at. Could be worth the cost (VM hackers can take the cost for the larger team of users). What do you think? /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: For Loop Desugaring (was: return when desugaring to closures)
On Oct 14, 2008, at 7:17 AM, David-Sarah Hopwood wrote: This is subject to the criticism that the loop variable(s) are implicitly mutable in the update expression (only), when they were declared it to be const. My point was simpler: sometimes it is handy to write for (const x...) and have no fresh binding for x, even though the loop iterates. It's a corner case that falls out of parsing var x and const x using the same top-down procedure, so not rejecting const where var is allowed. It arguably simplifies both implementation and user modeling of the grammar. We could certainly reject for (const ...; ...; ...) loops if we saw this as an anti-use-case. No such criticism would apply to 'for each (const ...', though. Right -- this is pure win. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: For Loop Desugaring (was: return when desugaring to closures)
On Oct 14, 2008, at 7:17 AM, David-Sarah Hopwood wrote: Requirement 3 is met because var hoists to the enclosing function. Assuming that var hoisting is done before this expansion, yes. Absolutely -- var hoisting across lambdas to preserve TCP is prior magic, assumed by the (revised) lambda proposal. In principle it could be lambda coded but I don' t believe the result would be particularly illuminating. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: For Loop Desugaring (was: return when desugaring to closures)
On Oct 14, 2008, at 12:39 PM, Waldemar Horwat wrote: PS. What does lambda(x = y){...}() mean? Is it different from lambda(x){...}(y)? No. What does lambda(x = y){...}(z) do when z is undefined? Passes undefined bound to x. Undefined is not the same as missing. These are my answers based on past default parameter proposals from ES4 which met with approval at the Oslo meeting. Others will no doubt shout if they seem wrong. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: For Loop Desugaring (was: return when desugaring to closures)
On Oct 14, 2008, at 1:36 PM, Brendan Eich wrote: On Oct 14, 2008, at 12:39 PM, Waldemar Horwat wrote: What does lambda(x = y){...}(z) do when z is undefined? Passes undefined bound to x. Undefined is not the same as missing. Lest anyone think otherwise, missing means actual argument count is less than number of formal parameters. It's not yet another undefined- like value code. The implementation knows that lambda has arity 1 with a default parameter value. It knows the call passes an actual (that its value is undefined does not matter). So the default parameter value is not used. Default parameters are evaluated once when the lambda expression is evaluated. That the lambda is immediately applied in your questions' examples may make this point unclear. This is why my answer to your question: lambda(x = y){...}() mean? Is it different from lambda(x){...}(y) was No. But if you captured the lambda and applied it elsewhere to a different y (y in a different scope chain), this equivalence would not hold. Hope this is all non-controversial (modulo blunders on my part explaining it). /be___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 15, 2008, at 2:36 PM, Waldemar Horwat wrote: There is no such thing as a let expression. Let expressions in JS1.7 (Firefox 2+), based on the ES4 proposal. ES3- ish grammar: LetExpression : let ( VariableDeclarationList ) [lookahead ∉ {{}] AssignmentExpression produced from PrimaryExpression. It's mandatory because the grammar and semicolon insertion rules say so. Btw, to properly terminate a lambda expression you'd need *two* semicolons. Here's why one would be insufficient: f = lambda(x) x; (a + b) c; would parse the body of the lambda as the expression x;, the (a + b) as an argument to the lambda, and the rest as applying to the result of calling the lambda. What you'd want to write instead would be: f = lambda(x) x;; Expression closures in JS1.8 (Firefox 3+) do not have this problem. Using ES3's notation: FunctionDeclaration : function Identifier ( FormalParameterListopt ) FunctionBody FunctionExpression : function Identifieropt ( FormalParameterListopt ) FunctionBody FormalParameterList : Identifier FormalParameterList , Identifier FunctionBody : { SourceElements } [lookahead ∉ {{}] AssignmentExpression /be___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 15, 2008, at 6:13 PM, Brendan Eich wrote: On Oct 15, 2008, at 2:36 PM, Waldemar Horwat wrote: There is no such thing as a let expression. Let expressions in JS1.7 (Firefox 2+), based on the ES4 proposal. ES3-ish grammar: LetExpression : let ( VariableDeclarationList ) [lookahead ∉ {{}] AssignmentExpression Rather, LetExpression : let ( VariableDeclarationList ) AssignmentExpression /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Lambda vs. function
On Oct 16, 2008, at 1:55 PM, Waldemar Horwat wrote: var: Not an issue if you're not using var inside the lambda. Code generation that wants to use lambda would use var why? arguments: Again, not an issue if you're not using the arguments array. If a code generator is updated for lambda, then presumably it will be updated not to use the arguments array. Why assume that lambda is only for code generators? /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 16, 2008, at 1:20 PM, Waldemar Horwat wrote: I don't think you can come up with a consistent shift or greedy notion. Funny, yacc has had one for decades, used to resolve dangling-else. The one you may be thinking of will happily accept code such as let (a = 5) x + y.foo = 2; yet the Firefox code gives a syntax error for it despite it being parsable by your grammar. Cut the misattribution of your ideas to me, based on misinterpretation of your experiment. Here's what's going on: Firefox (SpiderMonkey, shown here via its REPL) throws an error: js y = {} [object Object] js let (a = 5) x + y.foo = 2 typein:2: SyntaxError: invalid assignment left-hand side: typein:2: let (a = 5) x + y.foo = 2 typein:2: ..^ This is an error required by ES3, but it is not a syntax error according to the ES3 grammar -- it is an error due to semantic checking done in the spec by PutValue: 11.13.1 Simple Assignment ( = ) The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows: 1. Evaluate LeftHandSideExpression. 2. Evaluate AssignmentExpression. 3. Call GetValue(Result(2)). 4. Call PutValue(Result(1), Result(3)). 5. Return Result(3). 8.7.2 PutValue (V, W) 1. If Type(V) is not Reference, throw a ReferenceError exception. 2. Call GetBase(V). 3. If Result(2) is null, go to step 6. 4. Call the [[Put]] method of Result(2), passing GetPropertyName(V) for the property name and W for the value. 5. Return. 6. Call the [[Put]] method for the global object, passing GetPropertyName(V) for the property name and W for the value. 7. Return. SpiderMonkey historically used SyntaxError, not ReferenceError, and throw at compile-time. This pre-dates ES1. Another example not involving let expressions: js a + b = c typein:1: SyntaxError: invalid assignment left-hand side: typein:1: a + b = c typein:1: ..^ From ES3 chapter 16: An implementation may treat any instance of the following kinds of runtime errors as a syntax error and therefore report it early: • Improper uses of return, break, and continue. • Using the eval property other than via a direct call. • Errors in regular expression literals. • Attempts to call PutValue on a value that is not a reference (for example, executing the assignment statement 3=4). You may object that we should throw ReferenceError not SyntaxError -- that is not entirely clear from the chapter 16 wording, but it is at most a bug unrelated to our disagreement, and it doesn't prove any claim that primary expressions ending in assignment expressions are ambiguous or unusable. So what's the real problem? I said it already. The problem is that you don't have a valid grammar. You have not demonstrated that claim. This one is invalid, so the code of the Firefox implementation is effectively the specification, and it's hard to reason about that. It's easy, you can do it ;-). Other examples: What does the following do? for (a = let (b = c) b in d) ... SyntaxError because no ; after first expression in for (;;) loop head. vs. for (a = let (b = c) b in d;;) ... Valid syntax. vs. for (a = let (b = c) b in d in d) ... SyntaxError because no ; after first expression in for (;;) loop head. Yes, you can chain in (relational) expressions within an AssignmentExpression. No, users are not flummoxed, or as far as we can tell in over two years even bothered, by this. Yes, it can be specified unambiguously. /be___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 15, 2008, at 1:28 PM, Mark S. Miller wrote: On Wed, Oct 15, 2008 at 12:31 PM, Dave Herman [EMAIL PROTECTED] wrote: Do you prefer (lambda Formals Block | lambda Formals Expression)? [Personally I'm fine with that.] Or do you oppose any lambda expressions at all? Or did you have something else in mind? My preference is lambda Formals? Block Since an invocation of the closure evaluates to its completion value, the only savings of introducing the Expression form would be a pair of curlies. This is too small a benefit to justify another case in the grammar. Further, in exchange for always requiring the curlies, we can make the formals optional. Once we've got lambda, we'll start using them for control abstractions, in which case the no-parameter form will become quite common. I'd rather be able to leave out the parens than the curlies. YMMV. This is admittedly subjective, but you did ask about preferences. Hi Mark, That's fair and closely reasoned, but I question the likelihood of zero-argument lambdas emerging in control abstractions favored by all that many users. For now I favor the lambda expression form as well as the lambda block form. You're right that much of this is subjective, not just personal but also speculative about what users will tend to use. Expression closures are already insanely popular in JS1.8, of course used only in Mozilla-specific code. They'd be even more winning as lambdas, whether zero args is common or not (six letter keyword instead of eight), but losing the braces is part of the win. The two shifted chars are not easy on some peoples' hands (ask Python hackers who are spared such RSI-inducing chords). The visual weight is less, to boot. Definitely my two cents, no more (possibly fewer ;-). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 16, 2008, at 3:33 PM, Brendan Eich wrote: SpiderMonkey historically used SyntaxError, not ReferenceError, and throw at compile-time. This pre-dates ES1. Another example not involving let expressions: js a + b = c typein:1: SyntaxError: invalid assignment left-hand side: typein:1: a + b = c typein:1: ..^ From ES3 chapter 16: An implementation may treat any instance of the following kinds of runtime errors as a syntax error and therefore report it early: • Improper uses of return, break, and continue. • Using the eval property other than via a direct call. • Errors in regular expression literals. • Attempts to call PutValue on a value that is not a reference (for example, executing the assignment statement 3=4). You may object that we should throw ReferenceError not SyntaxError -- that is not entirely clear from the chapter 16 wording, An implementation may treat any instance of the following kinds of runtime errors as a syntax error and therefore report it early seems clear enough: an implementation that does choose (may) to report the ReferenceError from 8.7.2 PutValue step 1 *must* treat that runtime error as a syntax error -- throw a SyntaxError, in other words. There's no SpiderMonkey bug here, and it would be incorrect to do other than change ReferenceError to SyntaxError when reporting the PutValue error at compile time. Again, this is not a grammatical error. The ES3 grammar is not enough to decide what syntax errors might result from feeding a given program source to an implementation. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 17, 2008, at 11:05 AM, Waldemar Horwat wrote: Brendan Eich wrote: Is this a perfectly valid for-in statement? for (a = b in c); Not according to ES3's grammar. An assignment expression is not valid on the left of the for-in's in: /IterationStatement /*:* * ...* * for ( */LeftHandSideExpression /*in */Expression /*) */ Statement/ * for ( var */VariableDeclarationNoIn /*in */Expression /*) (Note VariableDeclarationNoIn after var.) */Statement/ LeftHandSideExpression does not produce an unparenthesized AssignmentExpression, and if you parenthesize then PutValue will throw on the non-Reference result of the assignment, the ReferenceError at runtime which again can become SyntaxError at compile time. I accidentally took out the var in editing the message. It should have been for (var a = ...) Waldemar _ In that case the -NoIn sub-grammar should apply, extended to LetExpressionNoIn. So for (let (a = b) c in d); would do what you want. We would have to change SpiderMonkey for this edge case, but that is our problem (and unlikely to break anyone). /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Oct 17, 2008, at 11:30 AM, Brendan Eich wrote: In that case the -NoIn sub-grammar should apply, extended to LetExpressionNoIn. So for (let (a = b) c in d); Sorry, of course that should have been for (var a = let (b = c) b in d); /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: The trouble with ambiguous grammars
On Oct 17, 2008, at 12:25 PM, Waldemar Horwat wrote: Here's a clearer case that Firefox gets wrong (or your grammar gets wrong, depending on your point of view): function f() {return f} var x = 3; let (a = 1) a ? f : x++(); The grammar states that the last statement must evaluate to f. Firefox gives a syntax error. This is incorrect because the let expression up to the ++ is a PrimaryExpression so can be used as the left operand of a function call. Consider the simpler, let-expression-free test: js var a = 1, f = 2; js a ? f : x++(); typein:3: SyntaxError: missing ; before statement: typein:3: a ? f : x++(); typein:3: .^ (The error pointer is off by two, I'm filing a bug on that.) Safari and IE seem to agree (IE blames the correct column number, the one for the ( -- good for it). This is an error according to ES1-3 because x++ is a postfixExpression derived from PostfixExpression : LeftHandSideExpression LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] -- while expr() meaning call expr with zero arguments derives from CallExpression : MemberExpression Arguments and MemberExpression is never an unparenthesized PostfixExpression: MemberExpression : PrimaryExpression FunctionExpression MemberExpression [ Expression ] MemberExpression . Identifier new MemberExpression Arguments So your example with or without the leading let (a = 1) is not syntactically valid. In an ambiguous grammar, you also need to prove the negative: no *other* expansion can match that source program and shadow your expansions. Proving the negative causes trouble because a language extension could turn the mismatch into a match and because sometimes, as in the above case, you expected some other part of the grammar to shadow your expansions but it didn't. That's a good point, but it is not what is going on here. There is no valid sentence x++() produced by ES1-3's expression grammar. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: The trouble with ambiguous grammars
On Oct 17, 2008, at 3:39 PM, Brendan Eich wrote: On Oct 17, 2008, at 12:25 PM, Waldemar Horwat wrote: Here's a clearer case that Firefox gets wrong (or your grammar gets wrong, depending on your point of view): function f() {return f} var x = 3; let (a = 1) a ? f : x++(); The grammar states that the last statement must evaluate to f. Firefox gives a syntax error. This is incorrect because the let expression up to the ++ is a PrimaryExpression so can be used as the left operand of a function call. Er, you are right, I should have acknowedged this point. The rest of my post is about x++() not being a valid sentence, which supports your argument. While we don't have any usability problems, and torturous statements such as let (a = 1) a ? f : x++(); are not written by real users (they'd parenthesize to clear up things), I agree that we don't want the prove a negative problem. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss