Problems of ||==, ||=== etc. and an alternative

It is a branch from this big topic: Operators: ||==, ||===
if (a ||=== "first-comparison" ||=== "second-comparison" ||=== "third-comparison" ) ...
It has problems. It probably can't work because a ||=== "first-comparison" should return false to continue and the next check will compare with false.
I propose an operator for variants, for example | how it works in regex.
if (a ||=== "first-comparison" | "second-comparison" | "third-comparison") ...
Tell me what do you think about the problem and this proposal.

Or two variant operators to avoid adding new ||==, &&===, ||!=, ||> and others. For example, & - "and" variant, | - "or" variant. Then:
if (a === "first-comparison" | "second-comparison" | "third-comparison") ... if (a === "first-comparison" & "second-comparison" & "third-comparison") ...

Those tokens are already bitwise operators.

2 Likes

Ok, never used them. Then something different.
Maybe "-|" and "-&". Or "?|" and "?&".
Or "#" and "\". To be single symbol.
Or "|||" and "&&&". But too many symbols.

If your concern is that there's too many symbols, it seems far simpler to repeat the comparison - x ||=== y || x ||=== z rather than inventing a new kind of symbol?

But how will it work? What steps of execution? I could not build steps due to the problem described in the first post.

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

or && instead of ||, if that's the semantics you want. Personally i'd indent it like this for readability:

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

As I understand, a ||=== "first-comparison" should return something because both === and || return. What will it return?

Sorry I didn't realize this sooner, but ||=== isn't a thing, so that'll be a syntax error.

There's ||, ===, and ||=, the latter of which is an assignment operator.

The condition you want seems to be a === 'first' || a === 'second' || a === 'third'.

Then why the initial thread (Operators: ||==, ||===) has 37 posts if the ||= assignment was added in 2020?
Stop, there will not be ||=, only 2 and 3 =, not 1.
Anyway, it can be reversed: ===||. But the question is open: what will it return? I mean when chained. I could not find a solution that is why I propose a variant operator. But it doesn't give the ability to make different checks.

Agreed.

This ain't one, though.

You're treating it like a binary operator, which is not what was proposed in the original thread. It was meant to be syntax for expressing n-ary operations, with n >= 3. The expression (a ||== b ||== c) is not identical to ((a ||== b) ||== c), author suggested the latter would be syntax error.

Consider existing ternary conditional: (a ? b : c). You don't treat the ? and : as stand-alone operators, or require that a ? b be a sub-expression of its own that returns something.

And what are?

Why >= 3? Why not >= 2?

It is weird because JavaScript doesn't work so. And because both || and === return values.
a ? b : c may be considered as a single operation but not chains with ||== because the engines should remember the value of a and comparison result several times, not once. Engines do next steps basing on what was returned. a in a ? b : c returns boolean from itself. We don't see it but it is in the internal process. Such returns are required to let the engines know how to handle things.

Please read the original thread thoroughly. Your argument that it cannot work is akin to saying arrow function expressions cannot work, because both = and > return values, and when I write x => y => x + y, the x => y should return something to pass to the next step. x => y is not a thing in the parse tree of that expression, and => has nothing to do with = or >.

You're trying to solve a non-issue. All the examples involving ||== et al can easily be rewritten into existing syntax, proving that it can work.

Ignore the similarity of ||== to binary operators you know, and think of the comparison chain as a function call with hidden name and parentheses, and commas replaced with funny symbol soup. The only difference would be how many times operands are evaluated:

a ||== b ||== c // a, b evaluated 1x, c evaluated 0-1x
(_a=a) == b || _a == c // same as above
ternaryEqOrEq(a, b, c) // all evaluated 1x
v ||== okay ||== fine &&!= bad &&!= worse // v, okay evaluated 1x, rest 0-1x
((_v=v) == okay || _v == fine) && _v != bad && _v != worse // same as above
tetraryEqOrEqAndNeAndNe(v, okay, fine, bad, worse) // all evaluated 1x

BTW, this is similar to how optional chaining is transpiled into legacy JS. In foo?.bar, the sub-expression foo must be evaluated exactly once, but its value is needed 3 times: twice for checking it's not null or undefined, and then for the actual member access. Transpilers use a temporary for that: (tmp = foo) === null || tmp === void 0 ? void 0 : tmp.bar


Now to address your questions.

That was the original author's choice, and it kinda makes sense because for n == 2 the operation would be identical to a simple existing comparison. Whether you define (a ||== b) to be a syntax error, or identical to (a == b) is a bikeshedding matter.

For me, one issue is that the || or && in the first symbol is irrelevant:

// same thing:
A ||== B ||== C
A &&== B ||== C

I think a cleaner solution would be to only allow this n-ary comparison chain on the RHS of existing comparison operators in the grammar, so you'd have:

A == B ||== C
// note that this is NOT two binary operations;
// it's a ternary operation with operands A, B, C

Another issue is that the author considers the ability to mix different logical operations in one comparison chain a desirable feature. I think it's questionable at best. Here's an example by the author:

if( value ||=== allowed1 ||=== allowed2 &&!== forbidden )
// same as
if ((value === allowed1 || value === allowed2) && value !== forbidden)

Notice how in order to understand this code, you must resist the urge to apply logical operator precedence rules you know and be aware that the three pair-wise comparisons within this 4-ary chain happen in source text order (left-to-right).

Another thing that's unlike existing boolean operations, is that in mixed-logical chain, you cannot arbitrarily flip operands around "operators" without changing the outcome.

With same-logical chain, or with binary logical operators, changing A op B to B op A won't change the result (unless it depends on operand evaluation side-effects, of course). So you can easily check the forbidden value first:

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

But there's no way to rewrite the above with a single comparison chain as proposed, while maintaining the order of comparisons.

It is too much. Maybe you will start parsing symbols into glyphs? I am sure that it can't pass all 4 stages because no logical return values for steps for the engines.

Yes, but ||=== is combined unlike =>.

Another problem is that if no return values, if a ||=== "first-comparison" means comparing a with "first-comparison", then "first-comparison" ||=== "second-comparison" means comparing "first-comparison" with "second-comparison". The engines are not a magic wand, they need logical steps, as much as the specification.

It is just what should be. If no mixing, just create 2 variant operators what I propose to not create as much as 16 (if not more) combined operators.

I don't see any sense. Why if it is to skip repeating a to write it only 1 time, not 2, not 3 and so on. And I don't think that counting is a rightful thing at all. JavaScript doesn't work so.

It is just what I propose. Variant operators. Like ternary operations. Notice that it requires different operators, not only one. No sense in repeating == after. It is better to create 2 new ("or" and "and"), than 16 combined. But it doesn't allow to mix what is sad.

Yes. Even in not mixed. It is when non-strict comparisons.