valentinium at gmail.com (2017-04-13T02:25:30.715Z)
> One common JS problem is NaNs ending up in unexpected places, and it's often difficult to trace back where they came from. Getting a type error instead of a NaN would be nice. I’m not sure this would help with that. NaN may be the product of coercion, but NaN itself is a numeric value, and it can be produced without any type coercion, e.g. `Infinity/Infinity`, `(-1) ** 0.5`, etc. And the `===` operator is a strict, non-coercive comparison, but that doesn’t mean it throws type errors.
> One common JS problem is NaNs ending up in unexpected places, and it's often difficult to trace back where they came from. Getting a type error instead of a NaN would be nice. I’m not sure this would help with that. NaN may be the product of coercion, but NaN itself is a numeric value, and it can be produced without any type coercion, e.g. `Infinity/Infinity`, `(-1) ** 0.5`, etc. And the `===` operator is a strict, non-coercive comparison, but that doesn’t mean it throws type errors. On Wed, Apr 12, 2017 at 7:48 PM, felix <felix8a at gmail.com> wrote: > One common JS problem is NaNs ending up in unexpected places, and it's > often difficult to trace back where they came from. Getting a type > error instead of a NaN would be nice. > > I think this is a reasonable argument for being able to write > expressions with non-coercing operators, and this is why I'd lean > toward annotating an entire expression as non-coercing, instead of > doubling the number of operators. > > On Wed, Apr 12, 2017 at 9:25 AM, T.J. Crowder > <tj.crowder at farsightsoftware.com> wrote: > > 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- > symbolic-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 > >> > > > > > > _______________________________________________ > > 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/5bfc88d6/attachment-0001.html>