recursion in Array.join/toString
Hi, Apologies if I've missed something obvious, but is there any explicit specification of how this works in Mozilla: xs = [1, 2, 3]; xs[1] = xs; alert(xs.join()) // prints 1,,3 It even works when the recursion is less direct, like this: xs = [1, 2, 3]; ys = [1, xs, 3]; xs[1] = ys; alert(xs.join()) // prints 1,1,,3,3 Apparently Array.toString() returns empty string if it detects it is already inside an invocation of itself? Best regards, Michael ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
for-in evaluation order
Hi, Some quick testing with Firefox seems to show that for-in returns properties in the order they were added to the object, and some scripts on the web (eg. RaphaelJS) seem to depend on that, unless I'm horrendously misinterpreting them. This seems... bad? Are objects implicitly ordered, by implementation convention? Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: for-in evaluation order
Thanks Boris, Dmitry, Are objects implicitly ordered, by implementation convention? For implementations that have to deal with the web, yes. Okay, now I know what we have to do then :) Might I suggest that this be added to the spec, if only in an informative note, to save future implementers the trouble? Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: for-in evaluation order
Hi Andreas, Note that almost all implementations break for-in enumeration order for dense arrays, for some definition of dense. This is understandable and very sensible. If we try to specify something, implementors will probably object, and each implementation will have specific objections depending on their particular array and object representation. Ugh. Tempting to randomise the order for non-dense objects, or just beat developers with the clue-bat until they stop writing code that depends upon a consistent order :) Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Function declarations as statements
Hi, In ECMAScript, function declarations are SourceElements, but not Statements. This means that they can only occur at the top level, and may not be nested inside a block. However, browsers support function declarations as statements, and many scripts on the web seem to make use of this ability, especially after they have been minified. Is there a spec anywhere for how functions as statements should behave? Can they be rewritten to var + function expression, so that this: { function f() { return 17 } } becomes this: { var f = function() { return 17 } } When implementing non-standard features, it would be nice to do so in a standard manner :) Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Function declarations as statements
Hi Brendan and Allen, Thanks for the pointers. So for Harmony, we are reclaiming function in block (must be a direct child of a braced block) to bind a block-local name on block entry (so hoisting lives, but only to top of block -- so you can't emulate with var f = function ...). If we implemented this behaviour now, I think that would be sufficient to make JQuery and Raphaël work. Here is an example from JQuery that is giving us trouble: if (condition) { var val, props, ... ; function getWH() { ... this is the function ... } if ( elem.offsetWidth !== 0 ) { getWH(); } else { jQuery.swap( elem, props, getWH ); } return Math.max(0, Math.round(val)); } The getWH() function is declared in the block and only used in the block, so if we hoisted the definition to the top of the block there would not be any problems with this usage. Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
{ and } in regexps
Hi, Browsers seem to allow { and } to occur in regexps unescaped, if the position does not conflict with their use as a quantifier. For example: /foo|{bar}/ However, ES3 and ES5 forbid this, as PatternCharacter does not include { or } or any of the other significant punctuation. Given that every new implementation ends up having to do what all the existing implementations do, is there any reason for the spec to differ? Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
\$ in regexps
[sent this to es3.x-discuss by mistake, sorry for any duplicates] Hi, Is \$ valid inside regexps? For example: xs = /foo\$bar/.exec(foo$bar); This matches in Firefox. However, the spec would appear to forbid this interpretation, unless I'm confused again: IdentifierStart :: $ IdentifierPart :: IdentifierStart IdentityEscape :: SourceCharacter but not IdentifierPart CharacterEscape :: IdentityEscape AtomEscape :: CharacterEscape Atom :: \ AtomEscape From these rules it seems that \$ is forbidden, and the only way to match a $ is to use a HexEscapeSequence or UnicodeEscapeSequence. So is this a spec bug? It seems to be present in ES3 and ES5. Or a Firefox extension? Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Assigning to empty array/object literals
Hi, Firefox 3.6.8 supports the following expressions: [] = 3; and: {} = 3; Although this object-literal version will trigger a syntax error at block scope, and so needs to be written like this: x = ({} = 3); In any case, shouldn't both of these expressions be early syntax errors, as the left hand side can never be a reference? For comparison, non-empty array and object literals throw an error: [1] = 3; // SyntaxError x = ({foo: 1} = 3); // SyntaxError Bug in Firefox? Or subtlety of the spec that's gone over my head? :) Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Assigning to empty array/object literals
Hi Dmitry, Destructuring (or, regarding JS -- Non-strict pattern matching). Thanks, I was fooled by the fact the left hand side was empty :) Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
ES5: typo in Error.prototype.toString()
Hi, In ES5 15.11.4.4 Error.prototype.toString() states: 6. If msg is undefined, then let R be msg. I'm pretty sure that should say: 6. If msg is undefined, then let R be name. ie. if an Error object does not have a message property, then toString() will return the value of the name property, or Error if it doesn't have a name property either. This is what Mozilla currently does. Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Catching eval
Hi all, Any comments on this code: try { throw eval; } catch (x) { alert(x(3)); } It does not appear to throw an EvalError in Firefox 3.6.7, even though many other indirect uses of eval will. Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Basic Lambdas and Explicit Tail Calls Repackaged
Hi Yuh-Ruey, I was also under the impression that since lambdas were lighter functions that would be more efficient in time and/or space. Is there any optimisation that could be performed for lambdas, but couldn't be performed for normal functions? For example, it is easy to statically check that a function does not refer to 'this', or 'arguments' (right?) so in theory a function that does not use these features should not have to pay for them. Functions are mutable objects and could perhaps gain a potential speed boost in some circumstances by being immutable. But that could be achieved by a generic mechanism for making immutable objects, and does not require introducing a new type of function. Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Simple tail calls
Hi Peter, From what I understand, if lambdas are supposed obey Tenent's principle, then they cannot have a return statement/expression. Wrapping an expression in a lambda must not change the meaning of the program. the following would need to be equivalent. Right, I personally think this is unnecessary; functions don't follow this principle, after all. I think it makes sense for expressions to have the same meaning, but not control flow statements when moved into a new execution context. Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Basic Lambdas and Explicit Tail Calls Repackaged
Hi, I thought it might be good to package these two proposals together, as they are interrelated. It would be very much appreciated if anyone could point out major use cases that these proposals don't cover, or any other important issues that they might currently neglect. BASIC LAMBDAS Lambdas are similar to functions, but use the lambda keyword instead of function, always have a this value of undefined, and do not have an arguments object in scope. LAMBDA EXAMPLES: var x = lambda(n) { return n + 1 } var x = lambda fact(n) { if (n = 1) return 1; else return n * fact(n-1); }; EXPLICIT TAIL CALLS The JavaScript specification should require implementations to treat any ReturnStatement containing a CallExpression as a tail call, except in cases when the ReturnStatement is within a WithStatement or within a TryStatement. TAIL CALL EXAMPLES: function f() { return g(); // -- tail call! } function f() { g(); // -- not a tail call, no return keyword } function f(x) { with (x) { return g(); // -- not a tail call, inside with } } ADVANTAGE: Very easy to specify and very easy to implement. It does not require tail calls for CallExpressions which occur outside of a ReturnStatement, eliminating a big chunk of specification devoted to figuring out exactly what is or isn't a tail call position. It does not require scanning through a function to identify tail positions, so even the most basic interpreter operating directly on abstract syntax trees could still implement them easily. ADVANTAGE: It makes tail calls explicit. Using return f() is as close as you can get to introducing a new keyword, without introducing a new keyword. It makes it immediately obvious whether a call is a tail call or not. EIBTI. ADVANTAGE: Explicit tail calls preserve correctness. The only point of requiring tail call optimisation rather than leaving it optional is because the correctness of some code depends upon it. However, implicit tail calls are easily lost as code changes. Consider a tail call within a deeply nested block: function f() { if (cond) { if (cond) { ... g(); // -- supposed to be a tail call, but is it? } } minorCleanup(); // -- oh no! someone added this! } If tail calls use an explicit return, it is much harder to accidentally break them, or overlook them. If tail calls are essential to ensure the correctness of some code, they should be explicit in that code. NOTE: Does not preclude fancier optimisations. Implementations would be required to treat return calls as tail calls. However, they would be free to treat other calls as tail calls as well, or perform more complex optimisations such as introducing accumulator arguments to transform code into tail-recursive form. Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Basic Lambdas and Explicit Tail Calls Repackaged
Hi Eugene, Is your lambda proposal competing with http://wiki.ecmascript.org/doku.php?id=strawman:lambdas (gave me by Brendon)? It is a different proposal, I think it helps to have more than one proposal, in order to clearly see the different trade offs involved. Why would anybody want to use a lambda instead of a function? 2 characters less to type? What is the compelling reason, the super idea behind the lambda besides confusing programmers, and more things to implement by compiler writers? Well, that's a really good question, as lambdas don't sound sufficiently different to regular functions in this proposal to be worth doing. The lambda proposal on the wiki gives the following Why reasons: A simpler primitive underlying the language’s first-class functions. Removing 'this' and 'arguments' also gives a simpler primitive, but is it enough to bother with? Supports defining other features via desugaring without breaking equivalence with implicit features (arguments, this, return) — this is sometimes described as Tennent’s Correspondence Principle [ 1, 2 ]. Not clear what this means, or what benefit it brings to either JavaScript programmers or implementors. A well-tested feature of programming languages since time immemorial. JavaScript already has higher-order functions, and much fewer languages have lambdas where a return returns from the enclosing function. Supports tail calls more naturally than function. I don't see what's unnatural about explicit tail calls in functions. Simple, composable features like lambda are useful for other language features defined via desugaring/compiling other languages to ES/macros What do lambdas in the wiki have that lambdas-as-functions-without-this do not have? They seem to have more complexity, but I can't see how they are significantly more useful. Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
Hi Brendan, This is the other hazard with lambdas. The program equivalences Tennent's Correspondence Principle enables are good for refactoring, but bad for thinkos like the above. It seems like most of the problems come from lambdas being able to contain statements as well as expressions. If there were only lambda expressions, I think they would be much easier to reason about, but currently there is no way to embed loops in expressions, right? Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
This is all speculation, but here's my non-speculative claim: lambda syntax should not look so much like function syntax if return within the body behaves completely differently. We would want syntax very different from function (i.e., not lambda (args) {body} -- sorry, Peter Michaux). Or else we should revisit the wisdom of applying TCP to lambdas. I'm unconvinced that TCP needs to apply to statements; it seems like a more valuable property when applied to expressions, even though JavaScript is not referentially transparent to begin with. Anyway, these three options look good to me: (1) Expression lambdas: lambdas whose body is an expression. var x = lambda(y, z) y + z Solves the problem with completion leakage, solves the nested return/break/continue issue. However, quite limited in usage, and makes it difficult to use lambdas to replace functions as they can't contain loop statements. (Hello, recursion! :) (2) Function lambdas: objects just like functions, except no this or arguments, and perhaps some guarantees about tail calls? var x = lambda(y, z) { return y + z } This seems the easiest for programmers to understand, and avoids the return/break issues. It violates TCP for statements, but I don't think that really matters in practice; after all, so do functions. (3) Parametric blocks: where a block, possibly taking arguments, can be passed around as an object. The key use-case for this seems to be creating new control abstractions. I would argue that blocks should not be usable as expressions, and the completion value cannot be captured (unless using eval) for consistency with existing statement behaviour. var a = block { ... statements ... } var b = block(x, y) { ... statements using x and y ... } call b(1, 2); // this is a statement, not an expression Unfortunately, object literals also look like blocks, and there is no perfect syntax for this that fits neatly into the existing language. without using bulky keywords. While this option preserves TCP, I don't think JavaScript really needs this feature, and the power/complexity ratio doesn't measure up. I agree if lambda looks like function or is sold as a better function. If it looks more like a block, or something else, that might mitigate the return hazard. Michael Day wondered if we confined the body to an expression language -- that would eliminate the return hazard. I like options (1) and (2) above. The current proposal on the wiki feels like all three options mashed together, and I find it difficult make sense of it as a basic construct. Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
Hi Brendan, Please read http://wiki.ecmascript.org/doku.php?id=strawman:lambdas There is a lot of discussion over whether it is necessary to introduce syntax sugar instead of a lambda keyword, but is there any remaining controversy over the semantics of lambdas in JavaScript, or is that considered settled at this point? (To throw some more kerosene on the syntax fire, I would point out that fun for function nicely resembles var for variable: var x = fun y z = y + z; but it's not big deal :) Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
Hi Brendan, The main contention about lambdas ignoring syntax is whether the completion-value creates a hazard that needs to be treated somehow, or even judged as fatal to the proposal. Completion value, like the last thing to be evaluated in the lambda? What exactly is the nature of the hazard? (To throw some more kerosene on the syntax fire, I would point out that fun for function nicely resembles var for variable: var x = fun y z = y + z; but it's not big deal :) Not bad but you lost the necessary (destructuring, default parameters) parenthesized formal list. Right, an arguments list should still look like an arguments list: var x = fun (y, z) = y + z or with an identifier: var x = fun fact(n) = (x 2 ? 1 : n * fact(n-1)) I toyed with 'fun' instead of 'function' in 1995 but it would have been a misfit in the Java-esque/C-like keyword set, even with 'var' included. In an alternate universe, you might have used 'method' for functions with a 'this' value, saving two characters and the name function for real functions :) Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Why continue is not allowed outside iteration statements
Yes, you're right here. But why not write 'label: while (true) { ... continue label ...; break; }', to make it clear that there is an iteration? Yes, this would be clearer. Forward jumps are less problematic than backward jumps -- in terms of Dijkstra's argument, they do not require an index to keep track of the number of iterations. I agree. They are unnecessary though, given that one could write: label: do { ... break label; ... } while (false); Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss