Operators: ||==, ||===

Could we use chaining comparison operators?

Multiple comparisons:

if( a === "first-comparison" || a === "second-comparison" || a === "third-comparison )
    ...

Chained comparisons:

if( a ||=== "first-comparison ||=== "second-comparison" ||=== "third-comparison" )
    ...

The same syntax would work for &&.

This is such a common issue that I assume it has already been proposed and rejected, but I couldn't find the conversation.

The stack overflow question is 10 years old with 100k views.

2 Likes

Could this syntax be confusing with how it is different to the existing ||= operator?

It is a different operator. I don't confuse + with ++, so personally, I don't expect any issues with confusion.

I found some related threads:

Chained comparison syntax (No replies)

That was (rightly) rejected because:

  • The syntax: | val1, val2 | is ambiguous. It makes |'s interpretation dependent on its context. (Chained comparisons in Python are similarly ambiguous; hard to read.)
  • By grouping comparison targets into a list, | val1, val2 | , you are forced to do 1 operation on the entire list.

Chained comparisons like ||=== are lexically unambiguous. Presently, every single one will generate a syntax error. They can chain any sequence of logical comparisons.

Would you also suggest to make

if (a !== "first-comparison" && a !== "second-comparison" && a !== "third-comparison) …

into

if (a &&!== "first-comparison" &&!== "second-comparison" &&!== "third-comparison") …

?

Btw the first operand should not need ||/&&, if anything I'd want to read

if (a === "first-comparison" ||=== "second-comparison" ||=== "third-comparison") …
if (a !== "first-comparison" &&!== "second-comparison" &&!== "third-comparison") …

Would you also suggest to make...

Yes. Logical completeness is definitely necessary for operators to be useful.

the first operand should not need ||/&&, if anything I'd want to read...

I definitely understand the appeal, but grammar needs to be consistent, not contextual.
What do these mean?

if( ( a === b ) ||=== c ||== d === e || === f ) ...
//              ^Syntax error? Compare to a?
if( a === b ||=== c ||=== d === e ||=== f ) ...
//                        ^What is this? d===e? Does d compare to f?
//                          Or does ( a === ... ||=== d ) compare to f???

You could arbitrarily decide in the spec that they mean one thing or another. That would be bad.
Inconsistent grammar makes hard-to-read situations.

But all is not lost! Look at this. :-)

if( valueToCompare
    ||=== condition1
    ||=== condition2
    ||=== condition3 )

I like it, anyway.

But the point is: The moment you encounter your first ||===, you know that the fully evaluated value immediately to its left is the subject being compared in the list to follow. No glancing back further to the left or glancing up a line while realizing you misinterpreted the operator you looked at a second ago.

A chaining comparison operator takes the result of evaluating its left-hand-side expression and compares it to the result of evaluating every chaining-operator-delimited expression in the subsequent list.
That's also the most straight-forward way to code an algorithm for it, so it makes the most sense to me, at least.

Is array.includes() an option?

if (["first-comparison", "second-comparison", "third-comparison"].includes(a)) {
  // ...
}

No, for the same reason the |...| syntax is useless.
a ||=== b ||=== c &&=== d cannot be computed using any array functions like find() includes() or reduce().

if( a ||=== b ||=== c &&=== d )
if( ( ( a === b ) || ( a === c ) ) && ( a === d ) )

I'm not sure I understand the purpose of &&===,

a &&=== b &&=== c

in which case a can be both equal to b and c?

Yes. It's the same as the purpose of &&. Without it, you can't write logical statements.

in which case a can be both equal to b and c?

Yes. And the fact that you can't imagine a particular scenario in which you would need it is meaningless. In order for a logical processor to be useful, it must be complete.
(In this case, &&!=== is much more obviously useful. But you need the complete set.)

I understand

  • ||=== and
  • &&!===

but

  • &&=== and
  • ||!===

seem usless

You assert that one needs the complete set - can you share examples of prior art? other languages that have added a more "complete set" of equality syntax and how that works?

I don't understand the question. Chaining operators are rare, but equality operators are always complete. Why would you add an incomplete set of chaining operators. Can you give me an example of a language that, for example, allows OR operators, but not AND operators?

By which I mean: If chaining operators are to be added at all, they should be a complete set. I do not mean to imply that logic operators in JavaScript are incomplete and could be "more" complete. (I would have very serious programming problems if they were incomplete.)

Here are examples.

&&===

if( targetIndex &&=== currentIndex &&=== 0 )
if( ( targetIndex === currentIndex ) && ( targetIndex === 0 ) )
    //do not re-seek current index, already there
    //do not decrement, at beginning of memory

||!===

if( color ||=== transparent ||!=== clipColor )
if( ( color === transparent ) || ( color !== clipColor ) )
    //do not blit, color clipped or NOOP

I'm referring to chaining operators, yes. ||= and &&= aren't "chaining operators", they're a combination of a single operator, and assignment.

Just an idea to make this more generic, and to prevent the confusion with chained operators: These operators could work like the for-of loop, i.e. they are binary operators expecting an iterable at the right side.

x === "a" || x === "b" || x === c"

becomes

x ||=== ["a", "b", "c"]

which then could also be used to check for a value in native maps:

x ||=== map.values()

Of course, this seems to make the operator quite useless once we have iterator helpers

["a", "b", "c"].includes(x)
map.values().some(v => v === x)

As I and others have repeatedly said, that syntax forces you to use a single operator.

The simple comparison:

if( value ||=== allowed1 ||=== allowed2 &&!=== forbidden )

Is impossible with a syntax that uses a list. (This kind of comparison is also impossible using any of the existing boolean-capable array functions like includes(), reduce(), and find().)