tj.crowder at farsightsoftware.com (2017-04-12T16:27:49.808Z)
FWIW, I think the next steps for this discussion are: 1. To hear from people whether they feel the need for these operations in their everyday work. It's interesting, you so often hear people saying "Always use `===`, not `==`!" with...fervor...but apparently strict versions of the relational operators aren't (or weren't) on people's minds. :-) 2. To hear from implementers about the difficulty level of adding four more symbolic operators (`<=<`, `<==`, `>=>`, and `>==` or whatever they end up being). (I like my non-symbolic operators -- `lt`, `lte`, and such -- but I doubt they'd pass muster, for the reasons Brendan flagged up in the thread about infix functions.) If the answer to #1 is "meh," discussions of operators vs. functions is moot; nothing's going to happen. If the answer to #1 is "Oh yes, this would be really useful" and the answer to #2 is "Fairly straightforward", that's a solid steer as well, as is an "Actually, surprisingly hard" to #2 (and it would be surprising, at least to me, but what do I know about implementing a JavaScript engine). -- T.J. Crowder
FWIW, I think the next steps for this discussion are: 1. To hear from people whether they feel the need for these operations in their everyday work. It's interesting, you so often hear people saying "Always use `===`, not `==`!" with...fervor...but apparently strict versions of the relational operators aren't (or weren't) on people's minds. :-) 2. To hear from implementers about the difficulty level of adding four more symbolic operators (`<=<`, `<==`, `>=>`, and `>==` or whatever they end up being). (I like my non-symbolic operators -- `lt`, `lte`, and such -- but I doubt they'd pass muster, for the reasons Brendan flagged up in the thread about infix functions.) If the answer to #1 is "meh," discussions of operators vs. functions is moot; nothing's going to happen. If the answer to #1 is "Oh yes, this would be really useful" and the answer to #2 is "Fairly straightforward", that's a solid steer as well, as is a "Actually, surprisingly hard" to #2 (and it would be surprising, at least to me, but what do I know about implementing a JavaScript engine). -- T.J. Crowder On Wed, Apr 12, 2017 at 4:49 PM, Michael J. Ryan <tracker1 at gmail.com> wrote: > That's part of why I suggested it... My mention of Object.* Was mainly > that it could defer to a common base class/constructor implementation for > comparison. And that a string and number implementation should be > provided... > > I'm also good with having non-matching types return undefined while > matching types is a Boolean. > > Object.* could just defer to the prototype implementation of the first > value.. null or undefined always returning undefined. > > -- > Michael J. Ryan - tracker1 at gmail.com - http://tracker1.info > > Please excuse grammar errors and typos, as this message was sent from my > phone. > > On Apr 12, 2017 7:04 AM, "Darien Valentine" <valentinium at gmail.com> wrote: > >> > Personally I think `a < b` should just become a compile error if the >> types are not number. >> >> Breaking stuff aside, I think this is an important point. The fact that >> the LT/GT operators do work on strings is a source of bugs. As with default >> sort, I’ve seen code written a number of times where it was evident the >> author expected the behavior would be more like >> `Intl.Collator.prototype.compare`. >> >> Unless I’m missing some important common use case for comparing strings >> based on byte values (`assert('a' > 'B')`), I think `Number.gt`, >> `Number.gte`, `Number.lt`, `Number.lte` would be a good solution. >> >> On Wed, Apr 12, 2017 at 5:09 AM, T.J. Crowder < >> tj.crowder at farsightsoftware.com> wrote: >> >>> > Personally I think `a < b` should just become a compile error if the >>> types are not number. TypeScript? >>> >>> I'm not following you. JavaScript variables don't have types, so it >>> can't become a compile-time error; and making it one would *massively* >>> break the web. (Yes, you can use TypeScript to get types if you like, but >>> we're not talking about TypeScript.) >>> >>> > ...that's a separable concern which should not be part of the >>> operator's behaviour IMO... >>> >>> There's no talk of changing how `<` and `>` (or `<=` and `>=`) work. >>> >>> But just as we have `==` (loose, coercing) and `===` (strict, >>> non-coercing), the discussion is about having strict non-coercing versions >>> of `<`, `>`, `<=`, and `>=`. >>> >>> -- T.J. Crowder >>> >>> >>> On Wed, Apr 12, 2017 at 10:00 AM, Alexander Jones <alex at weej.com> wrote: >>> >>>> Personally I think `a < b` should just become a compile error if the >>>> types are not number. TypeScript? >>>> >>>> If you want to also check that they are both number (that's surely what >>>> we mean here and not that they are both string!) and return `false` if not, >>>> that's a separable concern which should not be part of the operator's >>>> behaviour IMO. It would appear to just mask fundamental typing errors, >>>> unless I am missing some perspective? >>>> >>>> Alex >>>> >>>> On Wed, 12 Apr 2017 at 09:02, T.J. Crowder < >>>> tj.crowder at farsightsoftware.com> wrote: >>>> >>>>> Grr, there's always something. I forgot to mention that solving this >>>>> with functions is an option because short-circuiting isn't an issue, both >>>>> operands have to be evaluated by these relational operators anyway. So >>>>> unlike the motiviations for infix functions or macros or whatever, we don't >>>>> have that issue here. >>>>> >>>>> -- T.J. Crowder >>>>> >>>>> >>>>> On Wed, Apr 12, 2017 at 8:56 AM, T.J. Crowder < >>>>> tj.crowder at farsightsoftware.com> wrote: >>>>> >>>>> Very interesting stuff so far. >>>>> >>>>> My take on some options, organized into sections: >>>>> >>>>> * Solving it in userland >>>>> * Using symbolic operators >>>>> * Using functions >>>>> * Using non-symbolic operators >>>>> >>>>> # Solving it in userland: >>>>> >>>>> Anyone wanting strict relational operators today can readily give >>>>> themselves functions for it: >>>>> >>>>> ```js >>>>> const lt = (a, b) => typeof a === typeof b && a < b; >>>>> ``` >>>>> >>>>> Usage: >>>>> >>>>> ```js >>>>> if (lt(a, b)) { >>>>> // ... >>>>> } >>>>> ``` >>>>> >>>>> So the question is whether the value of having a standard way of >>>>> expressing this is worth the cost of adding it? >>>>> >>>>> Playing into that is that various options come with varying costs: >>>>> >>>>> * Using symbolic operators has a cost, but doesn't change >>>>> fundamentals; I'm not an implementer, but I'd think the cost would be >>>>> fairly low (but non-zero). *Any* syntax change rattles parsing cages >>>>> everywhere, but syntax changes are now fairly regular occurrences in >>>>> JavaScript. >>>>> * Using functions means no new syntax, which means not rattling >>>>> parsing cages, and are polyfillable. >>>>> * Using non-symbolic operators rattles cages, and probably more >>>>> significantly than new symbolic ones, and has been rejected in the past >>>>> (`is`/`isnt`). >>>>> >>>>> So that's in the mix. >>>>> >>>>> # Using symbolic operators: >>>>> >>>>> ## Form >>>>> >>>>> The closest I can come to consistency with `==`/`===` and `!=`/`!==` >>>>> is: >>>>> >>>>> Loose Strict >>>>> == === >>>>> != !== >>>>> < <=< >>>>> > >=> >>>>> <= <== >>>>> >= >== >>>>> >>>>> We can think of the `=` in the middle as being what signifies the >>>>> strict type aspect. The second `<` and `>` on `<=<` and `>=>` are a hack, >>>>> but a reasonable hack that's in the spirit of the original two strict >>>>> operators. :-) >>>>> >>>>> ## Semantics >>>>> >>>>> Because they're like `!==` and `===`, their semantics would have to be >>>>> in line with `!==` and `===`: The result is `true` if the operands are of >>>>> the same type and the relation is true, `false` otherwise. >>>>> >>>>> # Using functions: >>>>> >>>>> ## Form >>>>> >>>>> Given `Object.is(value1, value2)` there's an argument for putting >>>>> these on `Object` as well. But `Object` is an odd place for them (and >>>>> indeed for `is`). Perhaps we need a place for these to go. But sticking >>>>> with `Object` for now: >>>>> >>>>> ```js >>>>> Object.lt(value1, value2) >>>>> Object.gt(value1, value2) >>>>> Object.lte(value1, value2) >>>>> Object.gte(value1, value2) >>>>> ``` >>>>> >>>>> So: >>>>> >>>>> ```js >>>>> if (Object.lt(a, b)) { >>>>> // ... >>>>> } >>>>> ``` >>>>> >>>>> Verbose, and again, using `Object` if I'm comparing numbers or strings >>>>> seems wrong. But it's consistent with the prior practice of `Object.is`. >>>>> >>>>> Michael J. Ryan suggested putting them on `Number`, `String`, and >>>>> `Object` instead, on the theory that if you're being strict, you know what >>>>> you're comparing. I'm not sure I agree that you do (a generic "take the >>>>> lower of these two" function, for instance), but there's something there. >>>>> It doesn't address the verbosity issue. (Presumably we only need `Number` >>>>> and `String` though, unless we're going to introduce a whole mechanism for >>>>> relational comparison of objects. Or unless the `Object` version just hands >>>>> off to the `Number` or `String` version based on the first operand type.) >>>>> >>>>> ## Semantics >>>>> >>>>> Using functions gives us the opportunity to use slightly different >>>>> semantics: >>>>> >>>>> 1. `true`: The operands are the same type and the relation is true >>>>> 2. `false`: The operands are the same type and the relation is false >>>>> 3. `undefined`: The operands are of different types >>>>> >>>>> This takes advantage of the fact `undefined` is falsy to not get in >>>>> the way of people just using the result in a condition, but if they examine >>>>> the result itself, it's possible to differentiate between #2 and #3. >>>>> >>>>> Sadly, `Object.is` (the exposed version of the SameValue algorithm) >>>>> does not make this distinction. >>>>> >>>>> # Non-symbolic operators >>>>> >>>>> JavaScript already has at least one binary operator that isn't >>>>> symbolic: `in`. Maybe there's a case for adding more. Brendan Eich is [on >>>>> record](https://esdiscuss.org/topic/suggestion-mapping-symbo >>>>> lic-infix-ops-to-binary-functions#content-5) five years ago as having >>>>> issues with them: >>>>> >>>>> > > modulo, div, divmod, has, extends >>>>> >>>>> > These are much better as methods. Polyfillable, but also not subject >>>>> to weird line terminator restrictions on the left. Same arguments killed >>>>> is/isnt. >>>>> >>>>> Hence `Object.is`, presumably (the linked discussion was about infix >>>>> functions, not `is`). I don't know if that view has shifted in the >>>>> subsequent five years; there have been big changes in the way JavaScript >>>>> moves forward. But that was an objection at least then. >>>>> >>>>> ## Form >>>>> >>>>> `lt`, `lte`, `gt`, and `gte`. And while we're at it, `eq` and `noteq`. >>>>> So: >>>>> >>>>> ```js >>>>> if (a lt b) { >>>>> // ... >>>>> } >>>>> ``` >>>>> >>>>> To avoid breaking the web, the new non-symbolic operators would have >>>>> to remain valid identifiers, only being operators by context, a bit like >>>>> how `for` can be a literal property name (`obj.for`) as of ES5 because we >>>>> know from context that it's not the `for` statement. But I assume (not >>>>> being a parser guy) that it's more complex to handle the above (those >>>>> "weird line terminator conditions on the left" Eich mentioned). >>>>> >>>>> ## Semantics >>>>> >>>>> Like functions, non-symbolic operators let us consider slightly >>>>> tweaking the semantics, e.g. that `undefined` result for operands of >>>>> different types I mentioned earlier. >>>>> >>>>> # Wrap-up thoughts >>>>> >>>>> Unless it's left to userland, the simplest, least cage-rattling >>>>> approach is to add functions to `Object`, but it's also ugly to use. It >>>>> does have the benefit (in my view) of letting us tweak the return value >>>>> when the types don't match. >>>>> >>>>> It seems to me the second least cage-rattling is to add symbolic >>>>> operators consistent with `===` and `!==`. >>>>> >>>>> -- T.J. Crowder >>>>> >>>>> On Wed, Apr 12, 2017 at 7:05 AM, Michael J. Ryan <tracker1 at gmail.com> >>>>> wrote: >>>>> >>>>> Thinking on it... (Number|Object|String) >>>>> .strict(Equal|Greater|Less...) Methods (a, b) might be better... If either >>>>> value isn't a match for the bound type, it's a false, even if both sides >>>>> are equal... >>>>> >>>>> Ex,. >>>>> >>>>> Number.strictEqual(null, null) false >>>>> >>>>> Object.strictEqual(1, 1) false >>>>> ... >>>>> >>>>> If you're doing a strict compare, one can presume you should know what >>>>> you're comparing. >>>>> >>>>> >>>>> -- >>>>> Michael J. Ryan - tracker1 at gmail.com - http://tracker1.info >>>>> >>>>> Please excuse grammar errors and typos, as this message was sent from >>>>> my phone. >>>>> >>>>> On Apr 11, 2017 10:46 PM, "felix" <felix8a at gmail.com> wrote: >>>>> >>>>> Maybe every operator can have a non-coercing variant? >>>>> >>>>> One possible syntax is to have a modifier on operators >>>>> x = a (<) b (+) c (&&) (!)d; >>>>> if (x (!=) y) ... >>>>> >>>>> Another possible syntax is to have a modifier on expressions >>>>> x = #(a < b + c && !d) >>>>> if #(x != y) ... >>>>> >>>>> On Tue, Apr 11, 2017 at 7:48 PM, Darien Valentine < >>>>> valentinium at gmail.com> wrote: >>>>> > Although I’m unsure if this is wise given there are already eleven >>>>> symbols >>>>> > that are combinations of `=` and `<`/`>`, for symmetry with `==` and >>>>> `===` >>>>> > I’d imagine something like this: >>>>> > >>>>> > ``` >>>>> > COERCIVE STRICT >>>>> >> =>= >>>>> > < =<= >>>>> >>= =>== >>>>> > <= =<== >>>>> > ``` >>>>> > >>>>> > Could also follow the pattern `>==` (strict GT) and `<===` (strict >>>>> GTE), >>>>> > which avoids the awkwardness of the latter two sharing opening chars >>>>> with >>>>> > `=>`, but that seems more ambiguous since `>==` doesn’t let you infer >>>>> > whether it means strict GT or strict GTE. >>>>> > >>>>> > It’d be nice to have this functionality built in, but I wonder if >>>>> it’d >>>>> > possibly be preferable to provide it through methods of one of the >>>>> built-in >>>>> > objects, rather than as operators. Functions after all are more >>>>> flexible. >>>>> > >>>>> > _______________________________________________ >>>>> > es-discuss mailing list >>>>> > es-discuss at mozilla.org >>>>> > https://mail.mozilla.org/listinfo/es-discuss >>>>> > >>>>> _______________________________________________ >>>>> es-discuss mailing list >>>>> es-discuss at mozilla.org >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>>> >>>>> _______________________________________________ >>>>> es-discuss mailing list >>>>> es-discuss at mozilla.org >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>>> >>>>> >>>>> _______________________________________________ >>>>> es-discuss mailing list >>>>> es-discuss at mozilla.org >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>> >>> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170412/27fba8ec/attachment-0001.html>