I've always thought allowing a < b < c would be a net win for all languages that didn't coerce operandees of bool expressions into bools (think allowing 0 == false). In javascript this expression 3 > 2 > 1 is false, since it is true > 1 which is like saying 1 > 1. Not good. But in Roc, it would be a type mismatch (modulo the syntax error that right now notifies you to disambiguate with parens), so you wouldn't have to worry about this case. We could desugar this expression to a < b && b < c. I propose this sugar for these operators (<, <=. >, >=, == and != ). I think == and != are more debatable, but I would still include them, for completeness' sake.
At the same time, it is a small feature. It saves some &&s (or ands) to type, but the bigger discussion should be around Does this make the code more readable?. I think it doesn't make the code less understandable, not even with operator overloading (as long as we require them to return booleans). I haven't used a language that has it, like python or julia. I'm interested what you think about this feature in those languages and why you think it would or wouldn't have a place for it in Roc.
Do we plan on requiring that the desugared method of a.equals(b) -> c requires that b is of type a and c is of type Bool?
If so, this could be pretty helpful!
I expect more likely that we wouldn't raise an error at the equals method definition site that it has the wrong type, but more that the calling site would have a problem when equals returns a non-Bool and the == sign is used
And we could definitely use something like CalledVia internally to provide a better error message
On the subject of readability, this is probably a readability improvement for any list in the same direction, e.g. your a < b <= c
Yeah, I would only consider this feature if those rules would apply when using the comparison operators, whether enforced at the function definition, or at the use of the operator (tho I think the former would be a better experience "equas can only be defined if ..." than to say "MyNumber doesn't expose an equals function that has type MyNumber, MyNumber -> Bool" (while you actually have a function with a different signature.
As long as we enforce good ordering sounds reasonable. It is a nice feature.
I have seen someone write the equivalent of x < 7 > y and I never want to allow that in roc.
Brendan Hansknecht said:
As long as we enforce good ordering sounds reasonable. It is a nice feature.
I have seen someone write the equivalent of
x < 7 > yand I never want to allow that in roc.
Agreed.
this seems reasonable to me in the case of less than/greater than combinations
I don't think we should do it for others, including ==
like 0 < x <= 10 is nice
I don't think anyone looks at that and goes "what are these arcane runes? Rewrite this as 0 < x && x <= 10 so I can understand it"
but x == y == z doesn't seem like it would come up as often, and also makes me think they're all booleans
What about reverse ordering? 10 >= x > 0
I could see an argument for parsing that and then reformatting it to be the other way, as long as they aren't expressions that would be lazily evaluated
hm, actually that's interesting - should those short-circuit? :thinking:
the fact that it isn't obvious just from looking at it makes me think maybe it's better not to support it, actually :sweat_smile:
at least with and and or the semantics are clearly defined
even if it is more verbose
This is something we should maybe re-evaluate once we get some operator overloading + static dispatch usages in the wild
it definitely feels very low-impact either way haha
like having it or not having it doesn't seem impactful
Which is why I'd lean away from it
"don't add unimportant features" is definitely the right default, yeah :big_smile:
We should add stuff that we think is a positive, not likely to be a positive. A small language takes constant pruning efforts
For me, looking at it, short circuiting is "obviously happening", but yeah, you can't see the explicit &&s, so it isn't a no-brainer.
All arguments are good. To have a more definitive answer, before I mark as resolved, I'll ask: Which way are you leaning towards:
I lean more towards one. Definitely not a bad feature, just not sure if enough people would end up using this.
I lean towards 1. It's relatively low cost (totally optional to do, easy to understand if you see it even if you didn't know it was possible) and I think the benefits are small but certain.
In a past life teaching python to college students I saw beginners make this mistake all the time, cuz x < y < z is used in math classes, and it'd be nice if that speedbump didn't exist.
And it's another thing that would make Roc faster and easier to write for quick scripts.
But I do see the risk in adding every feature that seems like a good idea. In this case it makes it less clear what counts as an expression.
we could have the parser accept it and then special-case an error for it that tells you what to write instead
and have the formatter auto-replace it with and
Seems like it wouldn't be that hard to extend that out of our PrecedenceProblem reporting
Can the formatter fix your code this way? Thought it wasn't allowed to change the resulting AST - a restriction we ourselves put on it though. My first thought is that if we consider that, I would rather see it allowed in the compiler, since it is even less gain for ... quick estimation about something I have 0 experience in ... a relatively similar effort.
I had the same intuition as @Sky Rose . It just makes sense if you've seen it in math.
Last updated: Jun 16 2026 at 16:19 UTC