T.J. Crowder (2017-04-12T08:02:02.000Z)
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
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170412/f768697e/attachment-0001.html>
tj.crowder at farsightsoftware.com (2017-04-12T08:07:14.380Z)
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 motivations for infix functions or macros or whatever, we don't
have that issue here.

-- T.J. Crowder