Chained comparisons from Python and CoffeeScript

# Andy Earnshaw (6 years ago)

I apologise if I'm making more suggestions that have been discussed in the past, I'm genuinely searching before I click the compose button and not finding anything!

I'd like to see this implemented, at least for greater/less than (-or equal to).

a < b < c
a <= b <= c

Desugars to

a < b && b < c
a <= b && b <= c

For a real-world example

var pos = element.getBoundingClientRect(),
     inView = 0 <= pos.left && pos.left <= window.innerWidth && 0 <=

pos.top && pos.top <= window.innerHeight;

Could be rewritten as

var pos = element.getBoundingClientRect(),
     inView = 0 <= pos.left <= window.innerWidth && 0 <= pos.top <=

window.innerHeight;

There's a lot to be said for readability, and each operand needs only be evaluated once, so it could help avoid the need for creating variables to store the result of a function or a getter (or prevent the need for either to be invoked more than once).

It's also supported (as the title suggests) by Python [1], Perl 6 [2] and CoffeeScript [3]. Those languages support chaining the equality operators too.

It's potentially a breaking change, because

0 < 1 < 1

evaluates to false in current implementations because

(0 < 1) < 1

However, I think we'd be hard pressed to find code like this with greater/less than or equality operators.

[1] docs.python.org/2/reference/expressions.html#not-in [2] en.wikipedia.org/wiki/Perl_6#Chained_comparisons [3] coffeescript.org/#comparisons

# Tab Atkins Jr. (6 years ago)

On Thu, Jul 18, 2013 at 4:34 PM, Andy Earnshaw <andyearnshaw at gmail.com> wrote:

It's potentially a breaking change, because

0 < 1 < 1

evaluates to false in current implementations because

(0 < 1) < 1

Luckily, this is false in the chained operations too, since "(0 < 1) && (1 < 1)" evaluates to false.

One problem is that in current Javascript, the equality and the comparison operators are at different precedence levels. Python puts them at the same level, so that chaining can be purely left-to-right. There's a decent chance that code does indeed depend on this, due to testing equality of a comparison with a bool (which is stupid, but people do it).

# Rick Waldron (6 years ago)

On Fri, Jul 19, 2013 at 1:35 PM, Tab Atkins Jr. <jackalmage at gmail.com>wrote:

On Thu, Jul 18, 2013 at 4:34 PM, Andy Earnshaw <andyearnshaw at gmail.com> wrote:

It's potentially a breaking change, because

0 < 1 < 1

evaluates to false in current implementations because

(0 < 1) < 1

Luckily, this is false in the chained operations too, since "(0 < 1) && (1 < 1)" evaluates to false.

One problem is that in current Javascript, the equality and the comparison operators are at different precedence levels. Python puts them at the same level, so that chaining can be purely left-to-right. There's a decent chance that code does indeed depend on this, due to testing equality of a comparison with a bool (which is stupid, but people do it).

While this is all true, the simple answer is:

var a = 1, b = 2, c = 3; a < b < c; // true

is already valid JavaScript and can't be co-opted to express new runtime evaluation semantics.

# Tab Atkins Jr. (6 years ago)

Well, that's a bad example, because it's true with chained operators too. Let c = 1.5, though, and you get different behavior.

This type of code is broken in the first place, though. Are we assuming that it's prevalent enough to cause problems?

# Rick Waldron (6 years ago)

It doesn't matter if you think my example is a "bad example", it's a valid expression per the language's existing grammar.

# Tab Atkins Jr. (6 years ago)

It certainly does, because we don't expose the parsing directly. If we change the interpretation of a piece of code, but it outputs the same or compatible values, we're fine. It's only when the observable results change incompatibly that we have to worry. In your example, you get a "true" regardless of the interpretation, which means you're not demonstrating a problem with changing the interpretation.

# Andy Earnshaw (6 years ago)

On 19 Jul 2013 20:21, "Tab Atkins Jr." <jackalmage at gmail.com> wrote:

Well, that's a bad example, because it's true with chained operators too. Let c = 1.5, though, and you get different behavior.

This type of code is broken in the first place, though. Are we assuming that it's prevalent enough to cause problems?

Well, I was hoping it wouldn't. I can't imagine anyone writing this kind of code unless they expect it to work in the same way as Python (and by chance it did when they tested).

# Rick Waldron (6 years ago)

On Fri, Jul 19, 2013 at 5:43 PM, Tab Atkins Jr. <jackalmage at gmail.com>wrote:

On Fri, Jul 19, 2013 at 2:22 PM, Rick Waldron <waldron.rick at gmail.com> wrote:

On Fri, Jul 19, 2013 at 3:21 PM, Tab Atkins Jr. <jackalmage at gmail.com> wrote:

On Fri, Jul 19, 2013 at 1:21 PM, Rick Waldron <waldron.rick at gmail.com> wrote:

While this is all true, the simple answer is:

var a = 1, b = 2, c = 3; a < b < c; // true

is already valid JavaScript and can't be co-opted to express new runtime

evaluation semantics.

Well, that's a bad example, because it's true with chained operators too. Let c = 1.5, though, and you get different behavior.

It doesn't matter if you think my example is a "bad example", it's a valid expression per the language's existing grammar.

It certainly does, because we don't expose the parsing directly. If we change the interpretation of a piece of code, but it outputs the same or compatible values, we're fine. It's only when the observable results change incompatibly that we have to worry. In your example, you get a "true" regardless of the interpretation, which means you're not demonstrating a problem with changing the interpretation.

You have completely missed my point, please refer to the grammar specification that has existed since the first edition, published in 1997:

MultiplicativeExpression : UnaryExpression MultiplicativeExpression * UnaryExpression MultiplicativeExpression / UnaryExpression MultiplicativeExpression % UnaryExpression

AdditiveExpression : MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpression

ShiftExpression : AdditiveExpression ShiftExpression << AdditiveExpression ShiftExpression >> AdditiveExpression ShiftExpression >>> AdditiveExpression

RelationalExpression : ShiftExpression RelationalExpression < ShiftExpression RelationalExpression > ShiftExpression RelationalExpression <= ShiftExpression RelationalExpression >= ShiftExpression RelationalExpression instanceof ShiftExpression RelationalExpression in ShiftExpression

EqualityExpression : RelationalExpression EqualityExpression == RelationalExpression EqualityExpression != RelationalExpression EqualityExpression === RelationalExpression (ES3+) EqualityExpression !== RelationalExpression (ES3+)

Unambiguously and in no uncertain terms, the following is a completely valid expression (ie. will not throw a SyntaxError exception):

100 % 1 < 1e1 > 0xff - 5 + (+5) < 10 > 1.5 - 1..toString() === (function() {}()) !== parseInt(1, 10) * 1 | 0 >>> 1; // 1

It doesn't matter if the parsing isn't exposed, or broken in the first place, or a bad example, or not what you want, there is a formally defined grammar in a published standard. Hopefully I've cleared up any remaining questions or previously unclear points.

# Tab Atkins Jr. (6 years ago)

On Fri, Jul 19, 2013 at 4:18 PM, Rick Waldron <waldron.rick at gmail.com> wrote:

It doesn't matter if the parsing isn't exposed, or broken in the first place, or a bad example, or not what you want, there is a formally defined grammar in a published standard. Hopefully I've cleared up any remaining questions or previously unclear points.

You seem to be stating that once something's been published for a while, it's frozen. In reality, only the web-exposed parts are, and then only the parts that the web actually depends on. We can potentially change everything else.

Thinking anything else is harmful, as it means you avoid thinking about possible good ideas just because you've arbitrarily ruled out certain classes of changes, despite there being no reason to avoid that change.

Standards exist for the sole purpose of helping interoperability, which we like because it makes it easier to do cool things. Don't put them on a pedestal they don't deserve.

# Claus Reinke (6 years ago)

I'd like to see this implemented, at least for greater/less than (-or equal to).

a < b < c a <= b <= c

Desugars to

a < b && b < c a <= b && b <= c

As a workaround, consider that ES6 arrow functions are going to make something like this readable:

function sortedBy(op,...args) {
  for(var i=1; i<args.length; i++) {
    if (!op( args[i-1], args[i])) return false;
  }
  return true;
}

console.log( sortedBy( (a,b)=>a<b,  2,3,4) );  // true
console.log( sortedBy( (a,b)=>a<b,  2,4,3) );  // false

console.log( sortedBy( (a,b)=>a<b,  2,2,3) );  // false
console.log( sortedBy( (a,b)=>a<=b, 2,2,3) );  // true

Claus

# Brendan Eich (6 years ago)

Tab Atkins Jr. wrote:

In reality, only the web-exposed parts are,

What is not web-exposed here, pray tell?

and then only the parts that the web actually depends on.

This is the part we can't determine. "The web" is not just the Google-indexable (by what user agent?) part, but paywalled and intranet content as well. I've written before that finding true positives helps reject a proposed incompatible change, but finding no positives does not prove that we can make the change.

Furthermore, the first browser to roll the dice and face breakage loses, making implementors generally unwilling to take even likely-small risks. This browser Prisoner's Dilemma can be helped by cooperation, e.g., among TC39ers, but even then only for a big enough payoff. See the typeof null == "null" attempt early in ES6 development for an example.

# Andy Earnshaw (6 years ago)

On Mon, Jul 22, 2013 at 5:25 AM, Brendan Eich <brendan at mozilla.com> wrote:

This is the part we can't determine. "The web" is not just the Google-indexable (by what user agent?) part, but paywalled and intranet content as well. I've written before that finding true positives helps reject a proposed incompatible change, but finding no positives does not prove that we can make the change.

Furthermore, the first browser to roll the dice and face breakage loses, making implementors generally unwilling to take even likely-small risks. This browser Prisoner's Dilemma can be helped by cooperation, e.g., among TC39ers, but even then only for a big enough payoff. See the typeof null == "null" attempt early in ES6 development for an example.

typeof null == "null" is a different case though. typeof is a requirement for checking the existence of pre-declared variables, so you could expect something like, if (typeof someVar === "object" && someVar === null), to appear at least in a few places on the web. Tab's saying that this proposal wouldn't break much (if anything) because code isn't written like this anywhere: it wouldn't be readable or reliable. Writing a < b < c in ES<=5 would be either stupidity or ignorance (in the case of the latter then this proposal would probably fix more code than it breaks). For equality, there might be a problem where code is written like, if (a === b === true), where a and b are something other than booleans. I could maybe see an outside chance that this appears somewhere on the web or an intranet, but maybe there's a way we can deal with it so it doesn't break backwards compatibility.

"use chained comparisons";, anyone? ;-)

# Bjoern Hoehrmann (6 years ago)
  • Andy Earnshaw wrote:

typeof null == "null" is a different case though. typeof is a requirement for checking the existence of pre-declared variables, so you could expect something like, if (typeof someVar === "object" && someVar === null), to appear at least in a few places on the web. Tab's saying that this proposal wouldn't break much (if anything) because code isn't written like this anywhere: it wouldn't be readable or reliable. Writing a < b < c in ES<=5 would be either stupidity or ignorance (in the case of the latter then this proposal would probably fix more code than it breaks).

If that code is interpreted reliably and the behavior is desired, there is no reason to assume that e.g. code obfuscators would not produce it.

# Claude Pache (6 years ago)

Two (or three) remarks:

(1) The following expressions are perfectly reasonable, where a, b, c, d are variables holding numbers, and y is a variable (not a literal) holding a boolean:

a < b == y
a < b == c < d

and even (although it demands some imagination):

a < b <= y

where x <= y is a hackish way to express the so-called material implication (x → y) as defined in: en.wikipedia.org/wiki/Boolean_algebra#Derived_operations

Even if we ignore the last expression, it would be surprising (for, e.g., people used to Python), if we change the meaning of a < b <= y but not the one of a < b == c < d, so we are probably bound to change the meaning of very reasonable expressions anyway.

(2) If we change the meaning of a < b < c, then someone will use

var a = 1, b = 2, c = 3;
a < b < c; // true

in newer browsers, then check

var a = 1, b = 2, c = 3;
a < b < c; // true

in older browsers, and will fail to notice that their code is broken. In order to mitigate that hazard (supposing we want to make the breaking change anyway), we may want to invalidate expressions like a < b < c in ES6 (throwing a Syntax Error) and redefine their meaning in ES7.

"use chained comparisons";, anyone? ;-)

(3) Instead of a "use chained comparisons" directive, I dream of an implicit "use perfect language" directive, where (1) typeof null === "null", (2) wrapper objects around primitives do not exist, (3) chained comparisons are implemented, (4) Date objects are not Y2K-broken by design, (5) Date objects are compared by value, (6) concatenation and addition are not conflated into one operator, (7) I am able to make coffee from within my preferred browser. :-)

# Andy Earnshaw (6 years ago)

On Mon, Jul 22, 2013 at 2:08 PM, Bjoern Hoehrmann <derhoermi at gmx.net> wrote:

If that code is interpreted reliably and the behavior is desired, there is no reason to assume that e.g. code obfuscators would not produce it.

Perhaps, but I think it's highly unlikely. It doesn't offer much obfuscation, considering that any third operand would certainly be truthy if the operator was greater than and falsy if the operator was less than.

On Mon, Jul 22, 2013 at 2:24 PM, Claude Pache <claude.pache at gmail.com> wrote:

Even if we ignore the last expression, it would be surprising (for, e.g., people used to Python), if we change the meaning of a < b <= y but not the one of a < b == c < d, so we are probably bound to change the meaning of very reasonable expressions anyway.

Well, as Tab pointed out, comparison operators have the same precedence in Python, whereas in JavaScript the equality operators have a lower precedence. So a < b == c < d is the same as (a < b) == (c < d). Only operators with the same precedence could be chained, where's the confusion in that? Python users still have to learn the same stuff when writing JavaScript.

(2) If we change the meaning of a < b < c, then someone will use

    var a = 1, b = 2, c = 3;
    a < b < c; // true

in newer browsers, then check

    var a = 1, b = 2, c = 3;
    a < b < c; // true

in older browsers, and will fail to notice that their code is broken. In order to mitigate that hazard (supposing we want to make the breaking change anyway), we may want to invalidate expressions like a < b < c in ES6 (throwing a Syntax Error) and redefine their meaning in ES7.

Yeah, I can see this being a problem. Invalidating in preparation to redefine doesn't sound like a great solution, though, because you'd still have the same problem when the next specification rolls around. Opt-in sounds like a better solution, if pragmas are to be entered into the specification then it could even become part of

use strict;
# Domenic Denicola (6 years ago)

From: Andy Earnshaw [andyearnshaw at gmail.com]

if pragmas are to be entered into the specification

They are not.

then it could even become part of use strict;

Or even better: it could become part of ./andys-transpiler myfile.andy.

# Tab Atkins Jr. (6 years ago)

On Sun, Jul 21, 2013 at 9:25 PM, Brendan Eich <brendan at mozilla.com> wrote:

Tab Atkins Jr. wrote:

In reality, only the web-exposed parts are,

What is not web-exposed here, pray tell?

The parser itself. Only the results of the parser are, in terms of observable program behavior and presence/absence of syntax errors.

and then only the parts that the web actually depends on.

This is the part we can't determine. "The web" is not just the Google-indexable (by what user agent?) part, but paywalled and intranet content as well. I've written before that finding true positives helps reject a proposed incompatible change, but finding no positives does not prove that we can make the change.

Furthermore, the first browser to roll the dice and face breakage loses, making implementors generally unwilling to take even likely-small risks. This browser Prisoner's Dilemma can be helped by cooperation, e.g., among TC39ers, but even then only for a big enough payoff. See the typeof null == "null" attempt early in ES6 development for an example.

Preaching to the choir, buddy - I've been standardsing for quite a while too. I'm not stating an opinion either way on whether this change would be possible, I'm just pushing back on Rick's incorrect statements about the primacy of an existing standard. Gotta keep good brain hygiene, you know.

# Claude Pache (6 years ago)

Le 22 juil. 2013 à 17:55, Andy Earnshaw <andyearnshaw at gmail.com> a écrit :

On Mon, Jul 22, 2013 at 2:24 PM, Claude Pache <claude.pache at gmail.com> wrote: Even if we ignore the last expression, it would be surprising (for, e.g., people used to Python), if we change the meaning of a < b <= y but not the one of a < b == c < d, so we are probably bound to change the meaning of very reasonable expressions anyway.

Well, as Tab pointed out, comparison operators have the same precedence in Python, whereas in JavaScript the equality operators have a lower precedence. So a < b == c < d is the same as (a < b) == (c < d). Only operators with the same precedence could be chained, where's the confusion in that? Python users still have to learn the same stuff when writing JavaScript.

In the three languages you have cited (Python, Perl6 and CoffeeScript), all comparison operators (both equality and inequality ones) can be chained together. Introducing only half-baked chaining in ES will be quite confusing. If we dare introduce chaining, which is already a disruptive change, we ought to go until the end and to adjust the precedence of relational and equality operators as well. (Actually, we would introduce an n-ary comparison operator.)

# Brendan Eich (6 years ago)

Andy Earnshaw wrote:

On Mon, Jul 22, 2013 at 5:25 AM, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote:

This is the part we can't determine. "The web" is not just the
Google-indexable (by what user agent?) part, but paywalled and
intranet content as well. I've written before that finding true
positives helps reject a proposed incompatible change, but finding
no positives does not prove that we can make the change.

Furthermore, the first browser to roll the dice and face breakage
loses, making implementors generally unwilling to take even
likely-small risks. This browser Prisoner's Dilemma can be helped
by cooperation, e.g., among TC39ers, but even then only for a big
enough payoff. See the typeof null == "null" attempt early in ES6
development for an example.

typeof null == "null" is a different case though. typeof is a requirement for checking the existence of pre-declared variables, so you could expect something like, if (typeof someVar === "object" && someVar === null), to appear at least in a few places on the web. Tab's saying that this proposal wouldn't break much (if anything) because code isn't written like this anywhere: it wouldn't be readable or reliable. Writing a < b < c in ES<=5 would be either stupidity or ignorance (in the case of the latter then this proposal would probably fix more code than it breaks).

You're committing a category error here. It doesn't matter why someone does something on the web, it matters how much the standard semantics are required by "working" code (scare quotes on purpose).

In other words, you can't reason about this a priori only and reach a conclusion that "we can get away with a breaking change". Such "we can get away with" claims require a posteriori experiments and potentially-market-share-losing results, too.

For equality, there might be a problem where code is written like, if (a === b === true), where a and b are something other than booleans. I could maybe see an outside chance that this appears somewhere on the web or an intranet, but maybe there's a way we can deal with it so it doesn't break backwards compatibility.

"use chained comparisons";, anyone? ;-)

We could add more pseudo-pragmas but they must not add runtime checks (so this one would be ok by that constraint), and we'll have a wicked fight justifying any additions that aren't strongly motivated.

# Brendan Eich (6 years ago)

Tab Atkins Jr. wrote:

On Sun, Jul 21, 2013 at 9:25 PM, Brendan Eich<brendan at mozilla.com> wrote:

Tab Atkins Jr. wrote:

In reality, only the web-exposed parts are, What is not web-exposed here, pray tell?

The parser itself. Only the results of the parser are, in terms of observable program behavior and presence/absence of syntax errors.

This is irrelevant, since the change you are proposing is a compatibility-breaking one, even though parse trees are not yet reflectable.

and then only the parts that the web actually depends on. This is the part we can't determine. "The web" is not just the Google-indexable (by what user agent?) part, but paywalled and intranet content as well. I've written before that finding true positives helps reject a proposed incompatible change, but finding no positives does not prove that we can make the change.

Furthermore, the first browser to roll the dice and face breakage loses, making implementors generally unwilling to take even likely-small risks. This browser Prisoner's Dilemma can be helped by cooperation, e.g., among TC39ers, but even then only for a big enough payoff. See the typeof null == "null" attempt early in ES6 development for an example.

Preaching to the choir, buddy - I've been standardsing for quite a while too.

So why were you preaching at Rick? I didn't want to reply, but at some point the one-sided arguing got to be too much.

Look, you're proposing an incompatible change, akin to typeof null's result change. It doesn't matter why people might write code you'd break, it matters how much code exists. That's an empirical question. Exhorting people here does nothing but annoy some of us.

# Brendan Eich (6 years ago)

Claude Pache wrote:

(Actually, we would introduce an n-ary comparison operator.)

Sounds like a function ;-). Did you have straw syntax in mind?

This reminds me (not the n-ary part, but the new operator bit)...

We could also introduce binary <=>, AKA "cmp", return -1, 0, or 1.

Imagine the sort fun:

a.sort((a, b) => a <=> b)

:-P. The win over using

a.sort((a, b) => a - b)

is that <=> would work as expected for string-typed a and b as well.

# Brendan Eich (6 years ago)

Andy Earnshaw wrote:

Yeah, I can see this being a problem. Invalidating in preparation to redefine doesn't sound like a great solution, though, because you'd still have the same problem when the next specification rolls around.

Right! Web browsers do not upgrade in lock-step, or even in a ban/redefine two-step. N old versions smear across the market.

Opt-in sounds like a better solution, if pragmas are to be entered into the specification then it could even become part of

use strict;

Your point applies here too, though. "use strict"; (did you forget the quotes) has meaning in ES5, no meaning before, and therefore not likely new meaning after ES5.

We do not plan to evolve "use strict". Nor do we plan to remove the quotes (we've considered that at harmony:pragmas, deferred from harmony:proposals -- note strikethrough). It's possible more pseudo-pragmas in quotes may be standardized but as noted: wicked fight, requiring lots of data and careful argumentation.

# Tab Atkins Jr. (6 years ago)

On Mon, Jul 22, 2013 at 12:42 PM, Brendan Eich <brendan at mozilla.com> wrote:

Tab Atkins Jr. wrote:

On Sun, Jul 21, 2013 at 9:25 PM, Brendan Eich<brendan at mozilla.com> wrote:

Tab Atkins Jr. wrote:

In reality, only the web-exposed parts are,

What is not web-exposed here, pray tell?

The parser itself. Only the results of the parser are, in terms of observable program behavior and presence/absence of syntax errors.

This is irrelevant, since the change you are proposing is a compatibility-breaking one, even though parse trees are not yet reflectable.

Of course. But Rick's argument against was justifying itself on the parser, not expectation of web-dependence on the results. Just trying to point out the correct thing to be arguing about.

and then only the parts that the web actually depends on.

This is the part we can't determine. "The web" is not just the Google-indexable (by what user agent?) part, but paywalled and intranet content as well. I've written before that finding true positives helps reject a proposed incompatible change, but finding no positives does not prove that we can make the change.

Furthermore, the first browser to roll the dice and face breakage loses, making implementors generally unwilling to take even likely-small risks. This browser Prisoner's Dilemma can be helped by cooperation, e.g., among TC39ers, but even then only for a big enough payoff. See the typeof null

"null" attempt early in ES6 development for an example.

Preaching to the choir, buddy - I've been standardsing for quite a while too.

So why were you preaching at Rick? I didn't want to reply, but at some point the one-sided arguing got to be too much.

Look, you're proposing an incompatible change, akin to typeof null's result change. It doesn't matter why people might write code you'd break, it matters how much code exists. That's an empirical question. Exhorting people here does nothing but annoy some of us.

You've lost track of who's suggesting what. I'm not suggesting anything - it was a proposal by Andy. I've brought up problems with the suggestion in the thread. This side-thread is about the fact that Rick shot down the idea not based on possible breakage, but on a pure "this would be a spec change" argument, which is not a valid argument in and of itself against a change. (It points to the possibility of web-compat issues which would prevent the change, but does not itself prevent anything.)

I just wanted to avoid letting a precedent stand of something being rejected purely on spec-conflict grounds. I didn't intend for the point to get confused like this.

# Brendan Eich (6 years ago)

Tab Atkins Jr. wrote:

Of course. But Rick's argument against was justifying itself on the parser, not expectation of web-dependence on the results.

It was clear enough (to me and I think others) that Rick was talking indirectly about web-dependence, but let's not get stuck here.

You've lost track of who's suggesting what. I'm not suggesting anything - it was a proposal by Andy.

Somehow I thought you were on board (you are a Pythonista :-P) -- sorry.

While I have you (and others here), I wish we had a code search engine strong enough to find patterns such as x < y < z and the like on the web. Anyone know of anything like that?

I've brought up problems with the suggestion in the thread. This side-thread is about the fact that Rick shot down the idea not based on possible breakage, but on a pure "this would be a spec change" argument, which is not a valid argument in and of itself against a change. (It points to the possibility of web-compat issues which would prevent the change, but does not itself prevent anything.)

You are misreading Rick. When you think someone is making a dumb point, try reading them a bit harder for meaning.

I just wanted to avoid letting a precedent stand of something being rejected purely on spec-conflict grounds. I didn't intend for the point to get confused like this.

No one here was confused, as far as I can tell. There were too many words and bruised feelings, though :-|.

# Bjoern Hoehrmann (6 years ago)
  • Brendan Eich wrote:

We could also introduce binary <=>, AKA "cmp", return -1, 0, or 1. Imagine the sort fun:

a.sort((a, b) => a <=> b)

:-P. The win over using

a.sort((a, b) => a - b)

is that <=> would work as expected for string-typed a and b as well.

In Perl <=> compares as if the operands had been converted to numbers

and the cmp operator as if the operands had been converted to strings. If you are suggesting to have <=> change behavior based on type in-

spection at runtime, that behavior might lead to subtle bugs when the array contains strings and numbers (e.g., you might expect swapping the operands is the same as reversing the result, but it might not be. Indeed, without specifying the exact sorting algorithm you might get different sort orders in different implementations due to differences in which values are compared in which order). Having two operators a- voids that.

The other day I published search.cpan.org/dist/List-OrderBy which takes a lesson from .NET and offers better syntax for multi-key sorts, my @sorted = order_by { ... } then_by { ... } @unsorted;. I ended up with a not-so-nice list of variants to support ascending and descending order and numeric and string comparisons. Thinking about that now makes me wonder if the Voyager holodeck has and requires an Arch console for advanced uses. In Haskell you would never write code like a.sort((a, b) => a <=> b) as, to paraphrase, a.sort(<=>) is

much more clear.

# Tab Atkins Jr. (6 years ago)

On Mon, Jul 22, 2013 at 3:19 PM, Brendan Eich <brendan at mozilla.com> wrote:

Tab Atkins Jr. wrote:

Of course. But Rick's argument against was justifying itself on the parser, not expectation of web-dependence on the results.

It was clear enough (to me and I think others) that Rick was talking indirectly about web-dependence, but let's not get stuck here.

If so, then cool, we can all drop that sub-thread. ^_^

You've lost track of who's suggesting what. I'm not suggesting anything - it was a proposal by Andy.

Somehow I thought you were on board (you are a Pythonista :-P) -- sorry.

Oh, I'm on board with the idea - I like the Python functionality, and have found it very useful in avoiding temporary variables just to check that a value is within a particular range. But I think there's a small but reasonable chance this would be web-breaking, and wouldn't push it unless someone with more power inside a browser is willing to push on this. (I'm merely a spec-writer.)

Also, I'm quite certain that changing the precedence of the equality and the comparison ops would be web-breaking, as I've used that fact before (specifically, comparing the result of two comparisons directly, as given in an example by Andy). I might be okay with just allowing chaining of same-precedence things, but it would be weird and different from the other languages that have this functionality.

While I have you (and others here), I wish we had a code search engine strong enough to find patterns such as x < y < z and the like on the web. Anyone know of anything like that?

Now that Google's Code Search is dead, I'm not aware of a good one. :/

# Brendan Eich (6 years ago)

Bjoern Hoehrmann wrote:

  • Brendan Eich wrote:

We could also introduce binary<=>, AKA "cmp", return -1, 0, or 1. Imagine the sort fun:

a.sort((a, b) => a<=> b)

:-P. The win over using

a.sort((a, b) => a - b)

is that<=> would work as expected for string-typed a and b as well.

In Perl<=> compares as if the operands had been converted to numbers and the cmp operator as if the operands had been converted to strings. If you are suggesting to have <=> change behavior based on type in- spection at runtime, that behavior might lead to subtle bugs when the array contains strings and numbers (e.g., you might expect swapping the operands is the same as reversing the result, but it might not be. Indeed, without specifying the exact sorting algorithm you might get different sort orders in different implementations due to differences in which values are compared in which order). Having two operators a- voids that.

Good point, I'd forgotten my Perl (what little I had ;-).

The other day I published search.cpan.org/dist/List-OrderBy which takes a lesson from .NET and offers better syntax for multi-key sorts, my @sorted = order_by { ... } then_by { ... } @unsorted;. I ended up with a not-so-nice list of variants to support ascending and descending order and numeric and string comparisons. Thinking about that now makes me wonder if the Voyager holodeck has and requires an Arch console for advanced uses. In Haskell you would never write code like a.sort((a, b) => a<=> b) as, to paraphrase, a.sort(<=>) is much more clear.

Yes, that's what I wanted to suggest, but I couldn't sell < in operand position (to use operator-precedence parsing -- shades of E4X). Operators as first-class functions are on the radar for value objects, but not yet proposed with this kind of syntax.

Thanks for setting me straight on cmp vs. <=>.

# Andy Earnshaw (6 years ago)

On Tue, Jul 23, 2013 at 7:52 PM, Brendan Eich <brendan at mozilla.com> wrote:

Andy Earnshaw wrote:

On Mon, Jul 22, 2013 at 9:08 PM, Brendan Eich <brendan at mozilla.com<mailto:

brendan at mozilla.com>> wrote:

     Opt-in sounds like a better solution, if pragmas are to be
    entered into the specification then it could even become part of

        use strict;


Your point applies here too, though. "use strict"; (did you forget
the quotes) has meaning in ES5, no meaning before, and therefore
not likely new meaning after ES5.

I didn't forget the quotes :-) I remembered reading the proposal at harmony:pragmas, but I didn't check the harmony:proposals page to see what its fate had been. I was thinking that an ES6 use strict wouldn't need to retain compatibility with ES5 because of the differing syntax. Even still, you raise a good point, changing the meaning for ES6 might have been confusing.

Did you mean to reply-all? Just checking.

Oops. Still not used to replying to mailing lists. I did this a couple of times on other threads and didn't realise why everyone was saying almost the exact same things I said as if I'd not said them!

 We do not plan to evolve "use strict". Nor do we plan to remove
the quotes (we've considered that at
http://wiki.ecmascript.org/**doku.php?id=harmony:pragmas<http://wiki.ecmascript.org/doku.php?id=harmony:pragmas>,

deferred from **doku.php?id=harmony:proposalsharmony:proposals-- note strikethrough). It's possible more pseudo-pragmas in quotes may be standardized but as noted: wicked fight, requiring lots of data and careful argumentation.

I would really like to see this; the one-time evaluation of each operand could eliminate the need for temporary variables and the shorter, more readable code just sweetens the deal. However, I think if we're going to introduce more pseudo-pragmas, they should probably provide a significant change like Claude indicated, fixing typeof null and several other improvements (although I'm not sure I agree with all his ideas for a "perfect language" ;-)).

I think he was making the point that "perfect" is not an option ("I am able to make coffee from within my preferred browser"). We almost certainly are not going to fork the language with a pragma, but if we do it will be new syntax, to choke old browsers. Otherwise the testing burden doubles (again; this happened with "use strict"; in ES5 due to its runtime semantic changes).

Yeah, I suppose it's not such a good idea forking the language at all.

# Brendan Eich (6 years ago)

Andy Earnshaw wrote:

On Tue, Jul 23, 2013 at 7:52 PM, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote:

We almost certainly are not going to fork the language with a
pragma, but if we do it will be new syntax, to choke old browsers.
Otherwise the testing burden doubles (again; this happened with
"use strict"; in ES5 due to its runtime semantic changes).

Yeah, I suppose it's not such a good idea forking the language at all.

The slow-mo, evolutionary web way: extend to provide coexisting new and old features, and deprecate the old. They fade away, leaving vestigial organs that might fade over time (or might be misunderstood and still be used somehow).

This ups the ante for linters, nearly-same-semantics compile-to-JS languages, and evolving JS as a compiler target to keep other languages nearly-same-semantics.

# Forbes Lindesay (6 years ago)

Perhaps there should be a spec somewhere for "misfeatures" like a < b < c which linters ought to all reject. It could then only include things that (if we could turn back time) we probably would've liked to see in 'strict mode', but can't because that ship sailed.

If certain features were always regarded as errors by linters, that would certainly discourage their use. The next step would be making chrome dev tools have a built in linter that warns about these pseuso-errors/spec-mistakes. Maybe if that goes well we'll be able to introduce the new semantics in 5 years time.

# Tom Van Cutsem (6 years ago)

2013/7/24 Forbes Lindesay <forbes at lindesay.co.uk>

Perhaps there should be a spec somewhere for "misfeatures" like a < b < c which linters ought to all reject. It could then only include things that (if we could turn back time) we probably would've liked to see in 'strict mode', but can't because that ship sailed.

David Bruant set up a repo to collect these: DavidBruant/ECMAScript-regrets

I don't think anyone wants to invest the time to create an actual "spec" for ES5 \ "misfeatures", but collecting them and learning from them is probably the next best thing.

# Brendan Eich (6 years ago)

Too much blank-slate-ism here for me. ES5 strict was not the opportunity:

  1. The clock would have to go back much farther if people actually wrote a < b < c, but we still lack evidence that this is much used. It could be, so we're loath to change its semantics incompatibly (and we won't want opt-in versioning, or "modes")...

  2. Just deprecating is not enough, especially if the feared "misfeature" from C via Java is not actually misused. We'd want to obsolete, to clear the decks for Pythonic chaining. But that is not in the cards (see 1).