Short Comparing proposal

# Felipe Nascimento de Moura (5 months ago)

I wonder if there is already a proposal for such thing or if it would be something interesting to be proposal:

The motivation: Let's say you have an object whose property you want to compare to 'a' or 'b':

if (object.property.secondProp === 'a' || object.property.secondProp ===
'b') {
  // do something
}

The proposal: Now, with this syntax you would be able to perform such comparisons in a much simpler, better to read approach:

if (object.property.secondProp === ('a' : 'b')) {
    // do Something
}

And with the advance of the Optional Chaining Operator claudepache/es-optional-chaining proposal, it would

get even better, like so:

// this:
if (object &&
    object.property &&
    (object.property.secondProp === 'a' ||
    object.property.secondProp === 'b')) {
  // ...
}

// becomes this:
if (object?.property?.secondProp === ('a' : 'b')) { ... }

Alternatives: I do know that we could accomplish that with other techniques, like:

['a', 'b'].includes(object.property.secondProp)

I just think it might be counterintuitive and having a syntax for a "short comparing" would be better for reading and understanding.

Would make ternary comparison even shorter, too:

let currentState = object.property.status === ('fail' : 'ok') ? 'done' :
'doing'

Please let me hear your thoughts on that :)

.

# Ryan Birmingham (5 months ago)

I like the idea, and I generally agree that your proposal would increase readability, but I'm not a fan of the colon in parenthesis. In this context, the colon looks like it should represent a member assignment of 'b' to 'a'.

-Ryan Birmingham

# Felipe Nascimento de Moura (5 months ago)

I see... we could perhaps think on some other approach.

What about: if (obj.prop.prop ?== 'a' : 'b')

This way, we have "?==", which is not too chocking once we already got "!==", and this kinda prepares the engine to deal with the next values as part of the comparison. Also, feels familiar due to " something ? 'a' : 'b' "

Personally, I don't feel that comfortable with this syntax. We could think on different a token as well

if (obj.prop.prop === (? 'a' : 'b')) // feels like a ternary, but without the first statement if (obj.prop.prop === ('a' | 'b'))) // could break the web once it is already valid syntax (although not very used) if (obj.prop.prop === ('a' :: 'b')) // perhaps a double colon

Anyways, open for suggestions :)

# Ryan Birmingham (5 months ago)

I have a handfull of questions on this proposal as well: How would your proposal look with three or four things to check against? Would the collection of things to check against be a variable? Would this be syntactic sugar to the array includes method, or would this be something entirely new?

-Ryan Birmingham

# kdex (5 months ago)

I actually don't think this is worth pursuing, as it can easily be implemented by libraries once we solve operator overloading, without adding new syntax:

if (1 < [2, 3])

Am 01.02.2017 um 18:12 schrieb Ryan Birmingham:

# T.J. Crowder (5 months ago)

The chief advantage I see to doing this with syntax is short-circuiting. Otherwise, you could use a helper function to achieve if (valueIn(object.property.secondProp, 'a', 'b')) quite readily. Short-circuiting makes this interesting, though I worry about it pulling its syntactic weight.

If the mechanism did short-circuiting (lazy evaluation), then this (using your syntax for now)...

if (object.property.secondProp === (foo() : bar())) {
    // do something
}

...wouldn't call bar if the property's value matches the return value of foo (just like x === foo() || x === bar() wouldn't).

That being the case, the syntax would have to be visually distinct from an array (as yours is) to avoid confusion, while still supporting arbitrary expressions and, ideally, spread syntax.

I notice that you've used a relational operator (strict equality, in this case) and then special syntax following it, rather than (say) if (x anyof ('a', 'b')). Is it your intention that other operators would work with it too? if (x > (a : b : c))? (Rather than if (x > a || x > b || x > c) or if (x > Math.min.call(Math, a, b, c)).)

Also, you've used || in your example. What about &&? Suppose I want to make sure that x is greater than all three values in a, b, and c? I wonder if we could keep the syntax general enough to handle both cases.

On syntax: I'm with Ryan about not being keen on the (x : y : z) syntax. Also, given that the values could be arbitrary expressions nested arbitrarily deep, it seems like the : after the first value is a bit late to be telling the parser what's going on. I wonder if we could do it earlier. (Also, : isn't a natural list delimiter to my mind...)

Hmmm, taking the || vs. && into it, one idea would be to put the logical operator immediately (other than whitespace) following the opening paren:

if (x === (|| 'a', 'b')) {

Equivalent to (but x is only evaluated once):

if (x === 'a' || x === 'b')

and

if (x > (&& foo(), bar())) {

Equivalent to (but x is only evaluated once):

if (x > foo() && x > bar())

(Starts feeling a bit like Lisp.)

I can't help but think: At a high level, operators are just functions with special syntax, multiple dispatch, and lazy operand evaluation. Setting aside the multi-dispatch aspect, what if we...had a way to lazily evaluate function arguments? It sounds simple, but it gets complicated fast for situations like this where the argument list varies in length. But potentially quite powerful, and plays into operator overloading should that happen...

-- T.J.

# Andrea Giammarchi (5 months ago)

Interesting. Would it play well nested too?

if (x === 2 || (x === 3 && y === 1));

// as

if (x === (|| 2, (&& 3, y === 1)))

?

# T.J. Crowder (5 months ago)

On Wed, Feb 1, 2017 at 7:06 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

Interesting. Would it play well nested too?

if (x === 2 || (x === 3 && y === 1));

// as

if (x === (|| 2, (&& 3, y === 1)))

?

:-) I think at that point we're just creating an alternate expression syntax for JavaScript, which we probably want to avoid... Having the operands be Expression productions should be sufficient (which wouldn't allow that kind of nesting).

-- T.J.

# Andrea Giammarchi (5 months ago)

I understand, but you can also ternary within a ternary so why would this have different capabilities ?

# Jeremy Darling (5 months ago)

This is an interesting concept, but reuse of ()'s and : will make it difficult to pin down, scale to other operators and communicate. Really the "inclusion" operator needs to be something that stands out, doesn't break existing spec, and won't kill new specs. Excuse my poor concept below, as it probably breaks existing spec.

if(x == ${(A || B) && C})

Reusing the template string format RHS to specify the basics is bad, but my brain won't give me another valid option. This allows you to also do complex logic in RHS and LHS comparison.

# T.J. Crowder (5 months ago)

On Wed, Feb 1, 2017 at 7:18 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

I understand, but you can also ternary within a ternary so why would this have different capabilities ?

Because if (x === (|| 2, (&& 3, y === 1))) is trying to use only half of the expression within another expression. But using a conditional within a conditional is using an entire expression within another expression, which is fine.

-- T.J.

# T.J. Crowder (5 months ago)

On Wed, Feb 1, 2017 at 7:18 PM, Jeremy Darling <jeremy.darling at gmail.com>

wrote:

This is an interesting concept, but reuse of ()'s and : will make it difficult to pin down, scale to other operators and communicate. Really the "inclusion" operator needs to be something that stands out, doesn't break existing spec, and won't kill new specs.

Completely agreed. The trick is finding that something. We're definitely out of single-character options, so something along the lines you describe would be better. $ is probably not going to be an option as the lead character, as it's an identifier character.

I don't know how the process works, though. Is it too early to be thinking about syntax? The first question probably has to be whether it's worth exploring new syntax in this area at all, then exploring what that syntax might be...

-- T.J.

# Jordan Harband (5 months ago)

It seems like a far more useful proposal (although much larger in scope) would be some concept of interface comparison, and then you could see if object matches "an interface that has an a and b property", but also if object is "arraylike", or "iterable", or a "thenable", etc.

# Sendil Kumar N (5 months ago)

This is a far more useful option and more sugary syntax. We can use <| as an identifier.


// <| ( operator, arguments )

if (object.property.secondProp ===  <|(||, 'a' , 'b')) {
    // do Something
}


if (object.property.secondProp ===  <|(&&, 'a' , 'b')) {
    // do Something
}

In case of testing nested


if (object.property.secondProp ===  <|((||, 'a' ,(&&, 'c' , 'b'))) {
    // do Something
}

Thanks

Sendil Kumar N

# Bob Myers (5 months ago)

I'm puzzled about what's wrong with the good old [a, b].some(x => x === object.property.secondProp). If you insist on sugarizing this (but why?), then it could be [a, b].some(=== object.property.secondProp), or even [a, b].||(=== object.property.secondProp). But again, why?

If you really want to write <|(||, I suggest you switch to APL.

-- Bob

# T.J. Crowder (5 months ago)

On Fri, Feb 3, 2017 at 6:51 PM, Bob Myers <rtm at gol.com> wrote:

I'm puzzled about what's wrong with the good old [a, b].some(x => x === object.property.secondProp). If you insist on sugarizing this (but why?), then it could be [a, b].some(=== object.property.secondProp), or even [a, b].||(=== object.property.secondProp). But again, why?

Well, or as the originator of the thread pointed out, [a, b].includes(object.property.secondProp).

As I pointed out earlier in the thread, I think the only real justification for syntax for this would be short-circuiting (lazy evaluation of the possible values to be matched against). For my part, I'm not at all sure it's a sufficient one for new syntax.

-- T.J.

# Bob Myers (5 months ago)

If you're worried about short-circuiting, then

[() => a, () => b].some(x => c === x())
# Bob Myers (5 months ago)

If you're worried about short-circuiting, then

[() => a, () => b].some(x => c === x())
# Claude Pache (5 months ago)

Le 3 févr. 2017 à 21:05, Bob Myers <rtm at gol.com> a écrit :

If you're worried about short-circuiting, then

[() => a, () => b].some(x => c === x())

Even shorter: (_ => _ === a || _ === b )(c)

But more seriously: Now you have another issue, namely readability.

# Felipe Nascimento de Moura (5 months ago)

I started the thread with this question because I thought exactly in both performance (short circuit) and readability.

I got a little bit lost in this thread here...looks like there are some other e-mails mixed to it!

But anyways, bear with me:

// the expression
let x = a || b;
// could be
let x;
if (a) { x = a; }
else { x = b; }

So...the operator "||" in THIS particular case is also just an alternative, and yet extremely useful (and used). It is short, and is it beautiful for reading. That OR could be the good old "if"! Even though, I use it everywhere I can.

// the expression
if (obj.prop.prop2 === 'a' : 'b' : 'c') { ... }
// could be
if (obj.prop.prop2 === 'a' || obj.prop.prop2 === 'b' || obj.prop.prop2 ===
'c') { ... }

I see the same feeling here...yes, we could use other approaches, we could use destructors using the keys of an object...we could use [].contains, [].some, switch/case...but this is a much more beautiful way of doing it :)

I don't think it would make sense for &&, once things are not supposed to be equal to two different values

Again, just a suggestion, but one thing I like in JavaScript is its readability and power of "deduction power". The first time I read a code using || in an assignment (and I had no idea what that was, much younger, learning by myself, not knowing english, with almost zero access to internet), it toke me about 5 seconds to "guess" its behavior...it simply makes sense.

Thanks.

# Felipe Nascimento de Moura (5 months ago)

(pasting it here...got kinda lost with some other e-mail mixing this thread) hi

I started the thread with this question because I thought exactly in both performance (short circuit) and readability.

Bear with me:

// the expression
let x = a || b;
// could be
let x;
if (a) { x = a; }
else { x = b; }

So...the operator "||" in THIS particular case is also just an alternative, and yet extremely useful (and used). It is short, and is it beautiful for reading. That OR could be the good old "if"! Even though, I use it everywhere I can.

// the expression
if (obj.prop.prop2 === 'a' : 'b' : 'c') { ... }
// could be
if (obj.prop.prop2 === 'a' || obj.prop.prop2 === 'b' || obj.prop.prop2 ===
'c') { ... }

I see the same feeling here...yes, we could use other approaches, we could use destructors using the keys of an object...we could use [].contains, [].some, switch/case...but this is a much more beautiful way of doing it :)

I don't think it would make sense for &&, once things are not supposed to be equal to two different values

Again, just a suggestion, but one thing I like in JavaScript is its readability and power of "deduction power". The first time I read a code using || in an assignment (and I had no idea what that was, much younger, learning by myself, not knowing english, with almost zero access to internet), it toke me about 5 seconds to "guess" its behavior...it simply makes sense.

Thanks.

On Thu, Feb 2, 2017 at 5:25 PM Jordan Harband <ljharb at gmail.com> wrote:

It seems like a far more useful proposal (although much larger in scope) would be some concept of interface comparison, and then you could see if object matches "an interface that has an a and b property", but also if object is "arraylike", or "iterable", or a "thenable", etc.

On Thu, Feb 2, 2017 at 12:46 AM, T.J. Crowder < tj.crowder at farsightsoftware.com> wrote:

On Wed, Feb 1, 2017 at 7:18 PM, Jeremy Darling <jeremy.darling at gmail.com>

wrote:

This is an interesting concept, but reuse of ()'s and : will make it difficult to pin down, scale to other operators and communicate. Really the "inclusion" operator needs to be something that stands out, doesn't break existing spec, and won't kill new specs.

Completely agreed. The trick is finding that something. We're definitely out of single-character options, so something along the lines you describe would be better. $ is probably not going to be an option as the lead character, as it's an identifier character.

I don't know how the process works, though. Is it too early to be thinking about syntax? The first question probably has to be whether it's worth exploring new syntax in this area at all, then exploring what that syntax might be...

-- T.J.

# T.J. Crowder (5 months ago)

On Fri, Feb 3, 2017 at 8:29 PM, Bob Myers <rtm at gol.com> wrote:

If you're worried about short-circuiting, then

[() => a, () => b].some(x => c === x())

Obviously, you're not telling anyone anything they don't know there. But as it's both ugly and inefficient...

-- T.J.