Namely for all comparison operators they should be allowed to be chained. The easy way of disambiguating them is since they are all binary operators just chain them with &&. Lastly, this can help with code clearness since the following can be avoided
let x = fn_long();
let y = fn_other();
if 5 < x && x < 10 && y <= x && 5 < y {
...
}
and replaced with:
if 5 < fn_other() <= fn_long() < 10 {
}
where the return values of any non_constant is held in reserve so that the function isn't called multiple times.
It's sounds problematic since bool already implements PartialOrd, PartialEq, etc. These operators would need to become hostile to any associativity, including their current one, which likely breaks some existing code, albeit code that perhaps rustfmt should change.
boolalready implementsPartialOrd
Huh. It does. I had to check for myself, since I couldn't believe anyone could have had such a terrible idea.
However, such chaining of operators is still possible to implement, since it's currently rejected as an error. I'm not saying I want it to be implemented, I'm actually against the idea, but it's not a technical problem.
At least for LT, GT, LTE, GTE boolean cannot be a type on a side of one of the operators.
Actually (1<0) < true compiles just fine. It's interesting that _"chained comparison operators require parentheses"_ currently, so yes parsing this works.
The best use case I've seen for this is a range bound, like lower <= x < upper. However, to me, that seems better done with Range::contains: https://github.com/rust-lang/rfcs/pull/1434
What other use cases would fit this, that wouldn't be more clearly written some other way?
I've no strong feelings on this since the compiler already prevents chained comparison operators. I'm curious though : What languages do this currently?
Python that I know of
@joshtriplett it's more useful for generic code than anything (also, every language I know of has the relational operators for bool)
@ubsan Did you mean to direct your response above to @le-jzr ?
In Python a < x < b is just sugar for a < x and x < b (although the resulting bytecode is slightly different). Counter-intuitively, a < x > b also works, so the comparison chaining is really just fusing at its heart.
Don't know enough to judge from the rustc implementation's perspective, though.
I feel like this could be an optional thing, enabled by some #[pragma]. I mean, we already special-case the parse, just add a few hooks to make it like the Python implementation. OTOH, there's also semantics to consider. Like, does this syntax short-circuit? If I write a < b < someComputation() and at runtime a >= b, will someComputation() run, or not? And do we allow this for chaining more than two compares (e.g. a < b < c < d)?
If it was to work like Python then in the first case the function would not run since the operators are lazy and I don't see why not allowing chaining of multiple compares since it would be like concatenating multiple comparisons with short circuit and
I meant more in the sense of "this adds unnecessary complexity to our language specification for a feature that's pretty much optional" But looking back, there's really no reason not to do it, certainly not if it's a #[pragma]-based opt-in.
@cramertj yeah lol, sorry.
Anyways, I like this idea, it's quite nice and follows, at least my, intuition.
cc #561.
Just to add that Julia also allows this https://docs.julialang.org/en/v1/manual/mathematical-operations/#Chaining-comparisons-1
It happens to support more unicode operators and so is even more useful. Example 2 ∈ [2,3] ⊆ [2,3,4] evaluates true.
In real world no one writes 1 < 2 >= -1 except for confusing readers. The most common cases only contain homogeneous chains. So the syntax in Julia seems very bad to me.
Most helpful comment
The best use case I've seen for this is a range bound, like
lower <= x < upper. However, to me, that seems better done withRange::contains: https://github.com/rust-lang/rfcs/pull/1434What other use cases would fit this, that wouldn't be more clearly written some other way?