I agree - that's certainly an easy place for beginners to trip up on.
I'll point out another possible solution.
For the "~|" syntax, the python language does this instead, which I know some people like:
1 in [foo, bar, baz]
Currently, in JavaScript, you can do [foo, bar, baz].includes(1) to get similar behavior.
I remember seeing another thread floating around, proposing to add an "of" operator that's pretty much a shorthand for .includes() - but I can't remember where it is.
None of this really helps to solve the "~&" case. For that scenario, it might feel more natural to be able to write something like a === b === c - this is also a syntax with python supports - it's too late to support that in Javascript though, because it already has a different meaning.
From my experience tutoring people who are just starting out, this is actually a common source of confusion. I've seen many people try to do exactly what the O.P. described to check if a specific element is X or Y.
When they try to do that, they just need to be taught to decompose their condition - instead of doing "a === b || c", they need to do "a === b || a === c". I'm not sure how much it would help to add a new ~| operator - it's still very possible that we go through the same process. They try to do "a === b || c", and they've got to learn to switch to the "~|" operator in this specific case.
In other words, I agree this is an assumption from natural language, but if it's one that every programmer has had to learn, then it'd be great to look into whether other languages have tried to mitigate this specific issue or not. If not, it's a strong argument that such mitigation isn't needed; if so, that might help inform what to consider for JS.
Well, I don't know of any programming languages that try to solve this.
I also think it's not an easy problem to solve (unless you do introduce two separate operators). This is simply because in English, "or" can really mean two different things, and what it means depends on context. Programming language can't be sensitive to context the same way (or, at least they shouldn't try to magically understand context).
So, perhaps that's why no languages (that I know of) have tried to hard to resolve this. The closet thing I can think of is the python "in" operator and the fact that you're allowed to do "x == y == z". Both of those features provide syntax to use the other form of "and" and "or" that languages don't directly support, without literally creating a second "and" and "or" operator.
It's too late to do the equal thing in JavaScript, but we certainly could add x of ['a', 'b'] if we wanted to (I don't have strong feelings for or against syntax like that). That sort of syntax provides a more natural outlet to express one's self, in a way that's closer to English. But, it's not like ['a', 'b'].includes('x') doesn't read like English either.
I think that first scenario might actually be possible to recreate in userland with the operator overloading proposal. Provide an all() function that returns a special object that has === overloaded on it.
Pretty sure equality can’t ever be overrideable, even in that proposal.
However, you could return a distinct symbol or object whenever all three weren’t equivalent, ensuring that comparing to it would always fail unless all three were the same.
@theScottyJam, I didn't mean this just for beginners. I feel there are real use cases for this, where we can introduce this syntax to improve readability.
We can use the logical OR when we need to...
validate multiple choice fields in a form,
do union type checking
And logical AND when we need to...
to check if a participant has a reserved name in a meeting (if we know the reserved name ahead of time, of course)
Actually, I've found that we can achieve the same thing as my first example using this.
(foo & bar & baz) === 1
I like the "of" thingy. But I feel unions are more powerful, as we are not limited to using just ===. We can use absolutely any comparison operator. Like here...
foo ~| bar > 18
We could use some instead of this (every for ~&). But I find them more verbose.
[foo, bar].some((i) => i > 5)
There are places where we can only use "of", like...
if (username of usernames) print("Reserved :(")
So I think both proposals can co-exist, and serve different purposes :)
It looks like a good idea, but that would be a totally different syntax. Also, if we were to allow that, we'll need to do the same for all the other comparison operators. Besides unions can only be used for logical operators. They are used in combo with comparison operators.
I find the examples with ~| and ~& a bit confusing. It's subjective, but the ~| evokes some kind of operation/relation between foo and bar, which is not the case, you're treating them independently.
I'd be more comfortable with a wordy syntax, like
if (all of (foo, bar) > 18) ...
if (any of (foo, bar) < 21) ...
(this imo better conveys the values are independent, and that the whole thing can short-circuit)
There are these really interesting things called vectorized operators in Julia:
syntax:
.<operator>
eg:
.+
.-
.*
.etc
They apply the operation on every element of an array.
so [foo, bar, baz] .=== 1
[foo === 1, bar === 1, baz === 1]
might not be what you've asked for; I just wanted to drop this in.
That could work, but then we'd be left with an array of booleans, which we would still need to consolidate into a single boolean by doing .every() or .some() afterwards.