Removing labels
Can we remove labels from the next version of the spec?
I'm not a fan of labels, at least not as a built-in language construct - I'd much prefer if the language was expressive enough to emulate such functionality when needed (that includes useable syntax), not to mention reducing the need for such features in the first place.
However, as long as Javascript has break and continue, ..
Am I missing anything? Or are there cases where labels allow you do something that's impossible without labels?
It seems that language features like lambdas have been shot down because of their interaction with break and continue. In brief, people want to be able to abstract over syntax phrases like the one marked with -| .. |- here, by wrapping it in some form of immediately called function and still have it behave as before:
while (..) { .. -| break; |- .. }
[aside: as far as I understand Tennent, this has nothing to do with his principles of correspondence or abstraction, which are often misquoted and conjured with in the archives]
Now, if we want to wrap that phrase into a function (not a syntax macro), then that function cuts through the while/break construct. Still, we can refactor the code a little to make that wrapping possible:
loop: while (..) { ..
switch ( -| function() { return 'break'; } () |- ) {
case 'break' : break loop;
case 'continue' : continue loop;
}
..
}
With this change, we are able to wrap code involving break or continue into a function (and move that function definition out of the loop body). Since the switch statement has its own break-target, we need the loop label, even though the original break did not have a label.
There are other ways to handle this situation, but this seemed to be the most direct way of expressing the intention, given that labels are not first-class values in Javascript.
Better alternatives welcome, Claus
I think since we can only break/continue to labels in a linear chain upwards, break could take a number for how many loops it should break. This could still be tested at compile time as well, but would lead to somewhat less readable code. It would however be incompatible with current label based breaks (easier to find an replace if a compiler warns you).
while(true) { while(true) { break 2; } }
Anywho, I don't personally like number based breaking, just throwing around ideas.
On 2011-04-09, at 04:33, Peter van der Zee wrote:
Am I missing anything? Or are there cases where labels allow you do something that's impossible without labels?
They let you write more literate code? I agree labels should be eschewed, except where necessary. But sometimes, you just need them. Here's some fairly complex algorithms from the OpenLaszo source that I think would be even more difficult to understand without their judicious use of labels:
svn.openlaszlo.org/openlaszlo/trunk/WEB-INF/lps/lfc/services/LzCSSStyle.lzs
Sure there are plenty of other ways to write this code, but I'm not convinced they are more maintainable.
We shouldn't be making backwards-incompatible changes for features just because they can be abused. Every feature can be abused. And simplifying the completion type is not even remotely an important goal.
Sometimes labels are just necessary. Sometimes you have a loop that needs an early return, and you're doing a switch inside that loop, and there's no way to break out of the loop without the label. Labels are even more important for code generators, which need to implement non-trivial control flow. The one hand giveth compiler writers tail calls, the other taketh away labels? I sure hope not!
But I'll try to resist writing long, impassioned defenses about uncontroversial features of the language. The barrier to making backwards-incompatible changes is high (see Brendan's "five fingers of fate"), and we should only consider removing extremely problematic features.
[aside: as far as I understand Tennent, this has nothing to do with his principles of correspondence or abstraction, which are often misquoted and conjured with in the archives]
AFAICT, this traces back to a blog post by Neal Gafter:
http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html
When people say "Tennent's correspondence principle" to mean something like "beta-conversion is semantics-preserving" I believe this post is where they got the impression that it has to do with Tennent. For better or worse, it seems to have stuck.
This would be brittle. Take all my arguments against the ^this feature discussed in an earlier thread and repeat them here. Labels work just fine (and better than numbers would) for this purpose.
On Sat, Apr 9, 2011 at 12:47 PM, David Herman <dherman at mozilla.com> wrote:
When people say "Tennent's correspondence principle" to mean something like "beta-conversion is semantics-preserving" I believe this post is where they got the impression that it has to do with Tennent. For better or worse, it seems to have stuck.
I haven't got the faintest clue what beta-conversion is, but Neal's post seems consistent with what I took away from that (extremely short) discussion in Tennent's book. I'd look it up now, but it's at my office and this is the weekend. :) What am I missing?
2011/4/9 David Herman <dherman at mozilla.com>:
[aside: as far as I understand Tennent, this has nothing to do with his principles of correspondence or abstraction, which are often misquoted and conjured with in the archives]
AFAICT, this traces back to a blog post by Neal Gafter:
gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html
When people say "Tennent's correspondence principle" to mean something like "beta-conversion is semantics-preserving" I believe this post is where they got the impression that it has to do with Tennent. For better or worse, it seems to have stuck.
I was sharing a cube with him then, and from chats with him, it seemed to be a term that the Java guys bandied about a lot but he may have been the one who popularized the usage of it.
I don't have Tennent's book handy either. But Neal's post claims:
"The principle dictates that an expression or statement, when wrapped in a closure and then immediately invoked, ought to have the same meaning as it did before being wrapped in a closure."
And IIRC, when you look it up in Tennent's book, it really doesn't say that. I think if you squint you can sort of see a connection, but it's not obvious.
But the particular program equivalence Neal was talking about (which Tennent does not specifically mention in his book) is as old as the lambda calculus (we're talking 1930's here). It's a special case of what's known as beta-equivalence (or often "beta-conversion" or "beta-reduction" or "beta-substitution") in the lambda calculus. For what's known as the call-by-value lambda calculus [1] it can be stated roughly like:
(lambda(x1, ..., xn) expr)(v1, ..., vn) = expr[x1 := v1, ..., xn := vn]
Using substitution (the "x := v" notation, meaning "substitute v into the expression wherever you see a reference to x") doesn't exactly work for JS, because it doesn't model the heap, but it doesn't much matter for the zero-argument case.
More generally, the idea of using program equivalences for reasoning about and designing languages is "bread and butter" for PL researchers. It's weird to see it attributed to a tiny passage of a book from the 80's.
Dave
[1] If you don't know what call-by-value means here, don't worry about it. It has nothing to do with call-by-reference, just an unfortunate overloading of terminology. Nothing to see here, move along.
On Apr 9, 2011, at 1:33 AM, Peter van der Zee wrote:
Can we remove labels from the next version of the spec?
Ok, this thread has not been a complete waste, but I'm going to suggest, strongly, we not start "let's remove feature X" threads. We are being careful about migration tax. I've written about counting the backward-compatibility breaks on five fingers, and four out of five must break via early (compile-time) errors. (The current exception is typeof null == "null".)
Removing labels just taxes well-written code, requiring a pointless rewrite using flag variables or worse. It also would break all the accidental labels of the form javascript:... that have leaped across the URL / script source barrier.
As Dave says, we're not going to go on random "I want to remove feature X because some have misused it" snipe hunts. (BTW, that is not why 'with' was removed from ES5 strict mode.)
- es-discuss
Realized, I didn't include the mailing list.
Can we remove labels from the next version of the spec?
Labels are only used for continue and break. I don't think I've ever had or seen a need for them (which does not mean they're unused, btw). They can be sugar insofar as to breaking a double loop at once. But at the same time they promote spaghetti coding. On top of that there's a decent impact on the specification. In fact, I'm a little surprised they were not excluded from strict mode.
So nothing would really change for label-less
continue
and break.Switch and iterations would not get an empty label (obviously) and the whole label stack could be stripped.
Furthermore the grammar for continue and break would be as simple as that for debugger. And the label statement would disappear (which is nice because at the start of a statement, if the first token is an identifier, you need to parse another token before being able to determine whether you're parsing a label or an expression).
The completion type (8.9) would no longer need to have three parameters, just two.
Am I missing anything? Or are there cases where labels allow you do something that's impossible without labels?