Strict Relational Operators

classic Classic list List threaded Threaded
33 messages Options
12
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Strict Relational Operators

T.J. Crowder-2
I'm sure there must have been discussions of adding strict relational operators (e.g., non-coercing ones, the `===` versions of `<`, `>`, `<=`, and `>=`), but I'm not having a lot of luck finding those discussions. Searching "strict relational site:https://mail.mozilla.org/pipermail/es-discuss/" and on esdiscuss.org doesn't turn up anything relevant.

Does anyone have a link handy? I'm not trying to start a new discussion, just keen to read what's already been discussed.

Thanks,

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Strict Relational Operators

Mark S. Miller-2
Hi T.J.,

I do not recall such a discussion. Please do start one! Thanks.


On Mon, Apr 10, 2017 at 2:47 AM, T.J. Crowder <[hidden email]> wrote:
I'm sure there must have been discussions of adding strict relational operators (e.g., non-coercing ones, the `===` versions of `<`, `>`, `<=`, and `>=`), but I'm not having a lot of luck finding those discussions. Searching "strict relational site:https://mail.mozilla.org/pipermail/es-discuss/" and on esdiscuss.org doesn't turn up anything relevant.

Does anyone have a link handy? I'm not trying to start a new discussion, just keen to read what's already been discussed.

Thanks,

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Strict Relational Operators

Isiah Meadows-2
In reply to this post by T.J. Crowder-2
I'm not sure there has been prior discussion. A lot of stuff has
already been discussed in depth, but that I don't think is one of
them.
-----

Isiah Meadows
[hidden email]


On Mon, Apr 10, 2017 at 3:47 AM, T.J. Crowder
<[hidden email]> wrote:

> I'm sure there must have been discussions of adding strict relational
> operators (e.g., non-coercing ones, the `===` versions of `<`, `>`, `<=`,
> and `>=`), but I'm not having a lot of luck finding those discussions.
> Searching "strict relational
> site:https://mail.mozilla.org/pipermail/es-discuss/" and on esdiscuss.org
> doesn't turn up anything relevant.
>
> Does anyone have a link handy? I'm not trying to start a new discussion,
> just keen to read what's already been discussed.
>
> Thanks,
>
> -- T.J. Crowder
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Strict Relational Operators

Michael J. Ryan
It's definitely an interesting idea...  Been trying to consider what character would be added to represent a strict comparison...  Perhaps @?

>@  <@  <=@ >=@ ...

Not sure how this might conflict with decorators...

--
Michael J. Ryan - [hidden email] - http://tracker1.info

Please excuse grammar errors and typos, as this message was sent from my phone.

On Apr 10, 2017 9:48 AM, "Isiah Meadows" <[hidden email]> wrote:
I'm not sure there has been prior discussion. A lot of stuff has
already been discussed in depth, but that I don't think is one of
them.
-----

Isiah Meadows
[hidden email]


On Mon, Apr 10, 2017 at 3:47 AM, T.J. Crowder
<[hidden email]> wrote:
> I'm sure there must have been discussions of adding strict relational
> operators (e.g., non-coercing ones, the `===` versions of `<`, `>`, `<=`,
> and `>=`), but I'm not having a lot of luck finding those discussions.
> Searching "strict relational
> site:https://mail.mozilla.org/pipermail/es-discuss/" and on esdiscuss.org
> doesn't turn up anything relevant.
>
> Does anyone have a link handy? I'm not trying to start a new discussion,
> just keen to read what's already been discussed.
>
> Thanks,
>
> -- T.J. Crowder
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Darien Valentine
In reply to this post by T.J. Crowder-2
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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Felix-54
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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Michael J. Ryan
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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

T.J. Crowder-2
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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

T.J. Crowder-2
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 <[hidden email]> 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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Alexander Jones
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

T.J. Crowder-2
> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Darien Valentine
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Michael J. Ryan
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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

T.J. Crowder-2
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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Felix-54
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
<[hidden email]> 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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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
>>> <[hidden email]> 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 <[hidden email]> 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
>>>>> <[hidden email]> 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
>>>>>> <[hidden email]> 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 <[hidden email]>
>>>>>>> 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 - [hidden email] - 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" <[hidden email]> 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
>>>>>>>>> <[hidden email]> 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
>>>>>>>>> > [hidden email]
>>>>>>>>> > https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>> >
>>>>>>>>> _______________________________________________
>>>>>>>>> es-discuss mailing list
>>>>>>>>> [hidden email]
>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> es-discuss mailing list
>>>>>>>> [hidden email]
>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> es-discuss mailing list
>>>>>> [hidden email]
>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>>>
>>>
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> [hidden email]
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> [hidden email]
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Darien Valentine
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 <[hidden email]> 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
<[hidden email]> 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 <[hidden email]> 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 - [hidden email] - 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" <[hidden email]> 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
>>> <[hidden email]> 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 <[hidden email]> 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
>>>>> <[hidden email]> 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
>>>>>> <[hidden email]> 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 <[hidden email]>
>>>>>>> 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 - [hidden email] - 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" <[hidden email]> 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
>>>>>>>>> <[hidden email]> 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
>>>>>>>>> > [hidden email]
>>>>>>>>> > https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>> >
>>>>>>>>> _______________________________________________
>>>>>>>>> es-discuss mailing list
>>>>>>>>> [hidden email]
>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> es-discuss mailing list
>>>>>>>> [hidden email]
>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> es-discuss mailing list
>>>>>> [hidden email]
>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>>>
>>>
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> [hidden email]
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> [hidden email]
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Felix-54
On Wed, Apr 12, 2017 at 7:23 PM, Darien Valentine <[hidden email]> 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’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.

Mysterious NaNs in js are usually due to implicit conversion of random
objects to numbers, not normal numeric computation.

It's reasonable for non-coercing === to work on different types, but
what would a non-coercing + do with different types? It has to throw
an error.

Non-coercing < might throw an error or use some arbitrary ordering of
types. I don't have strong feelings about that.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

Darien Valentine
It's reasonable for non-coercing === to work on different types, but what would a non-coercing + do with different types? It has to throw an error.

Ah, didn’t catch that you were talking about non-relational operators as well. Assuming a strict `+` was still overloaded for string concatenation, yeah, an error makes sense (whereas if numeric only, NaN might also be considered a reasonable answer).

For strict `<`, etc, I think it would be unintuitive to get an error or to have arbitrary type order. Rather I’d expect it to be false when the types didn’t match, since, for example, the correct answer to both the questions "is seven greater than an object?" and "is an object greater than 7?" is "no". This would be consistent with the behavior of the existing always-incomparable value, NaN, as well. That said, I think an error would be better than having an arbitrary type order if those were the two choices.

On Thu, Apr 13, 2017 at 12:56 AM, felix <[hidden email]> wrote:
On Wed, Apr 12, 2017 at 7:23 PM, Darien Valentine <[hidden email]> 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’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.

Mysterious NaNs in js are usually due to implicit conversion of random
objects to numbers, not normal numeric computation.

It's reasonable for non-coercing === to work on different types, but
what would a non-coercing + do with different types? It has to throw
an error.

Non-coercing < might throw an error or use some arbitrary ordering of
types. I don't have strong feelings about that.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

T.J. Crowder-2
I've started a separate thread to discuss felix's idea of an expression mode making all operators within it non-coercing (as it's rather more broad than this topic): https://esdiscuss.org/topic/strict-non-coercing-expressions

-- T.J. Crowder


On Thu, Apr 13, 2017 at 6:58 AM, Darien Valentine <[hidden email]> wrote:
It's reasonable for non-coercing === to work on different types, but what would a non-coercing + do with different types? It has to throw an error.

Ah, didn’t catch that you were talking about non-relational operators as well. Assuming a strict `+` was still overloaded for string concatenation, yeah, an error makes sense (whereas if numeric only, NaN might also be considered a reasonable answer).

For strict `<`, etc, I think it would be unintuitive to get an error or to have arbitrary type order. Rather I’d expect it to be false when the types didn’t match, since, for example, the correct answer to both the questions "is seven greater than an object?" and "is an object greater than 7?" is "no". This would be consistent with the behavior of the existing always-incomparable value, NaN, as well. That said, I think an error would be better than having an arbitrary type order if those were the two choices.

On Thu, Apr 13, 2017 at 12:56 AM, felix <[hidden email]> wrote:
On Wed, Apr 12, 2017 at 7:23 PM, Darien Valentine <[hidden email]> 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’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.

Mysterious NaNs in js are usually due to implicit conversion of random
objects to numbers, not normal numeric computation.

It's reasonable for non-coercing === to work on different types, but
what would a non-coercing + do with different types? It has to throw
an error.

Non-coercing < might throw an error or use some arbitrary ordering of
types. I don't have strong feelings about that.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Re: Strict Relational Operators

James Treworgy
I am of the opinion that this isn't really a worthwhile effort in the context of a non-typed language. There are several issues.

First, it doesn't actually create any parity with ===. Triple equals never throws an error, it just returns false if the types are unequal. These constructs would change the way the language works fundamentally in that an expression can cause an error which it currently cannot.

Second, it really just provides a kind of "too late" poor man's type checking. What you really wanted was a guard when the variable was created or the argument passed.  It may provide little help about the actual source of the bug.

New syntax and the complexity it creates seems a high price to pay for a little band aid. 

If we were going to add some simple syntax to try to help this problem without going full typescript/flow then I'd be much more in favor of simply adding type guard clauses to function arguments that are evaluated at runtime.


On Apr 13, 2017 2:44 AM, "T.J. Crowder" <[hidden email]> wrote:
I've started a separate thread to discuss felix's idea of an expression mode making all operators within it non-coercing (as it's rather more broad than this topic): https://esdiscuss.org/topic/strict-non-coercing-expressions

-- T.J. Crowder


On Thu, Apr 13, 2017 at 6:58 AM, Darien Valentine <[hidden email]> wrote:
It's reasonable for non-coercing === to work on different types, but what would a non-coercing + do with different types? It has to throw an error.

Ah, didn’t catch that you were talking about non-relational operators as well. Assuming a strict `+` was still overloaded for string concatenation, yeah, an error makes sense (whereas if numeric only, NaN might also be considered a reasonable answer).

For strict `<`, etc, I think it would be unintuitive to get an error or to have arbitrary type order. Rather I’d expect it to be false when the types didn’t match, since, for example, the correct answer to both the questions "is seven greater than an object?" and "is an object greater than 7?" is "no". This would be consistent with the behavior of the existing always-incomparable value, NaN, as well. That said, I think an error would be better than having an arbitrary type order if those were the two choices.

On Thu, Apr 13, 2017 at 12:56 AM, felix <[hidden email]> wrote:
On Wed, Apr 12, 2017 at 7:23 PM, Darien Valentine <[hidden email]> 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’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.

Mysterious NaNs in js are usually due to implicit conversion of random
objects to numbers, not normal numeric computation.

It's reasonable for non-coercing === to work on different types, but
what would a non-coercing + do with different types? It has to throw
an error.

Non-coercing < might throw an error or use some arbitrary ordering of
types. I don't have strong feelings about that.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
12
Loading...