8 ms·
My favorite language is Javascript, so I've got plenty of warts to choose from. I think that the most intrusive one is semicolon insertion. This is perfectly
by IsaacSchlueter 18y ago
My favorite language is Javascript, so I've got plenty of warts to choose from.
I think that the most intrusive one is semicolon insertion. This is perfectly valid code that does not do what it looks like:
return
{
a: "foo"
};
That's quite different from:
return {
a: "foo"
};
- ars 18y agoThat's a pretty good argument to never use Allman, Whitesmiths, GNU, or Horstmann indent style. There can only be one and that's K&R. Woho! I just won a religious war.
- bayareaguy 18y agoTcl's string quoting conventions also try to force you to use K&R style for procedure bodies. e.g proc foo {x} { # do stuff } but if you really want to get around this you can abuse the continuation character proc foo {x} \ { # do stuff }
- IsaacSchlueter 18y agoAbsolutely! For Javascript at least, putting the { on the same line as the thing that caused it is pretty much the only rational policy. The weird thing is just how the interpreter handles this: return; { a: "foo"; } That's a null return, a block (not that JS supports block-level scope, so blocks are pointless), a labeled line (line-labels aren't actually used for anything, since there's no GOTO), and on that labeled line, there's a string expression that does nothing. So, this is really like 4 different warts working together, but semicolon insertion is by far the most insidious. Also, liberal use of parens can help prevent semicolon insertion bugs.
- cousin_it 18y agoMy favorite language is JavaScript too, and the most annoying wart for me is function scope instead of lexical scope. For example, var closures = []; for (var i = 0; i < 10; i++) { var j = i; closures[i] = function() { alert(j); } } closures[0](); // outputs 9, WTF? How to fix it: var closures = []; for (var i = 0; i < 10; i++) (function() { var j = i*i; closures[i] = function() { alert(j); } })(i) closures[0](); // outputs 0 as it should
- ars 18y agoFunction scope is the entire point of closures. If it was lexical scope it would not be a closure, it would just be a regular function. Just pass in j when you call it and you can have lexical scope easily. But if you changed that, a TON of code would be impossible, so I'm very happy with it working that way.
- cousin_it 18y agoNo. Function scope is the entire point of closures. If it was lexical scope it would not be a closure, it would just be a regular function. Many more languages with closures have lexical scope than function scope. Lexical scope is the entire point of closures in those languages, indeed everywhere except JavaScript. Just pass in j when you call it and you can have lexical scope easily. I don't know j when I call the closure. Give a code example. But if you changed that, a TON of code would be impossible, so I'm very happy with it working that way. I can't imagine any code that would become impossible, or even the slightest bit more difficult, if function scope were replaced with lexical. Indeed all code using function scope could be mechanically translated into a (hypothetical) lexically-scoped-JavaScript by moving every var declaration in every if/for/while/etc block up to the toplevel of the containing function. If you disagree, give a code example.
- IsaacSchlueter 18y agoYou could also do it like this: var closures = []; for (var i = 0; i < 10; i++) { var j = i; closures[i] = (function (k) { return function() { alert(k); })(j); } closures[0](); // outputs 0 The issue is that the var here is passed by reference. Ie, all 10 closures refer to the SAME "i" variable. So, when i is incremented, they see that it's been incremented. Outputing 9 is actually correct in the first case. If you want to trap the current value, you need to copy the value to a new reference, ie, by making it the argument of a function with a new scope.
- cousin_it 18y agoYeah I know how this stuff works per spec. The issue is that the var here is passed by reference. Ie, all 10 closures refer to the SAME "i" variable. So, when i is incremented, they see that it's been incremented. No, closures refer to the j variable that doesn't get incremented, only assigned to. The assignment is by value - no vars get "passed by reference", whatever this means. The actual issue is that all invocations of the loop body alias the same var j, even though it's declared inside the block. I usually wrap the whole loop body if it contains multiple variables and multiple closures closing over them - it's easier on the brain than fixing every closure creation spot. Kinda sad because JavaScript is almost the perfect language for my mind.