1

Virtually all (imperative) languages offer the operators < <= >= > for lower, lower or equal, greater or equal and greater. But why no ternary range operator like (10 < x < 100) to test if x is between 10 and 100 or an inclusive one 10 <= x <= 100. Would this make parsing prohibitively complicated? Or is there even a language that can do this?

9
  • 1
    btw this is the reason why in my programming practise I write such a test as (10 < x and x < 100) to perhaps make it more readable. But add and and more so duplicating the operand might be problematic.
    – theking2
    Mar 11, 2023 at 15:32
  • 5
    Python supports chaining like this for all binary comparison operators, where x < y < z has the same semantics as x < y and y < z except that y is only evaluated once.
    – Jasmijn
    Mar 11, 2023 at 15:44
  • @Jasmijn I did not know this. so this is perfectly possible. I tested this myself in the online ANTLR lexer/parser and could create a production rule by modifying the pascal syntax with good results. But still, why only python? I use the construct quit often.
    – theking2
    Mar 11, 2023 at 16:03
  • 2
    Possibly already answered over at SO here: stackoverflow.com/questions/4090845/… Mar 11, 2023 at 16:03
  • 1
    I assume the operator is also not in high demand because other semantics are simple to write and read. E.g., x in range(a,b). And for most applications, the overhead of the extra function calls to facilitate this is not significant.
    – svidgen
    Mar 11, 2023 at 22:18

3 Answers 3

5

Would this make parsing prohibitively complicated?

No, modern parsers are more than capable. But it does complicate the documentation, in order to explain the functionality to new users.

Or is there even a language that can do this?

Yes. Python, perl6, mathematica, and indeed all Turing-equivalent languages can do this. Not only the imperative ones you suggested, but pure functional ones, as well.

Python offers 10 <= f(x) < 100 expressions, which match math notation and are very convenient. In other languages you could sprinkle a bit of syntactic sugar on top, some simple pre-processing, to accomplish the same thing: temp = f(x); 10 <= temp and temp < 100. (Of course a hygienic temp var name would be needed.) In languages offering macros or functions, pretty much all of them, you could ask is_in_halfopen_interval(f(x), (10, 100)), perhaps with 3 args if tuples are not conveniently available.

(I am using the example of half-open intervals because of how nicely they compose, so they work well as API args.)

Given some scalars that should be strictly monotonic, python will happily verify that:

if a < b < c < d:

It comes down to custom and convention. If standard libraries provide and consume some "usual" way of expressing a concept, then apps within the ecosystem will follow that.

Let's ignore other kinds of numbers and focus just on intervals over integers. Python offers the range type to model this. (Assume for the moment step is always 1.) So you can assign r = range(10, 100) and then ask if int(f(x)) in r:

These ranges are a bit specialized since the emphasis is on producing subscript indexes. But lots of app functions are integer valued, so it can be very natural to request schedule(job_id, start_within=range(6, 9)), and the documentation burden is quite low due to use of the familiar range abstraction. In contrast someone designing an API like this: schedule(job_id, start_within=(6.5, 9)) would have to carefully describe the meaning of that generic tuple and whether 9.0 is a valid starting time (closed interval?) or not.

In summary, popular languages can and do support range operators.

3

From the parser’s point of view it’s no big deal. It may not fit nicely into a grammar, but who says we can only parse languages with a nice grammar?

You can actually parse it quite easily and distinguish between a<b<c and a<(b<c). Then when you turn the parsed grammar into code, you have to be careful.

But first you need to decide what are actual valid chains. We start with any number of expression separated by ==, !=, <= etc. which is not compatible for example with C where different operators have different priorities. The trivial case of one operator only should have the same result.

What about evaluating the expression? Either each operand is evaluated exactly once, or until the result is known. You decide.

Can < and > be mixed? Can == and != be mixed? In a != b != c, do all operands have to be different, or only a != b and b != c?

In Swift I believe this could be implemented in the standard library with quite strong demands on the optimiser.

3
  • intersting point.As a thought experiment how about an "in" operator with two operands x IN (l, h) would test exclusive and x IN [l, h] inclusive or even x IN ]l, h[ for exclusive. This would remove the ambiguity of the normal comparison operators and would document great if a basic math class was visited .
    – theking2
    Mar 13, 2023 at 21:26
  • That looks a bit like Pascal :-)
    – gnasher729
    Mar 14, 2023 at 21:05
  • Pascal is so underrated (all hail Niklaus Wirth)
    – theking2
    Mar 14, 2023 at 21:13
3

SQL has the Between operator: x BETWEEN y AND z.

The main problem with triadic infix operators within expressions, is distinguishing them from a series of dyadic infix operators.

That is, given x < y < z, it is ambiguous whether this is one operator (with three operands), or whether it is two operators (where the result of the first operation forms one of the operands for the second).

In the case of SQL, the ambiguity is resolved by there being no dyadic Between operator, as well as by other aspects of the language which restrict the context in which the dyadic logical-And can appear.

In C, there is no range comparison operator, but the conditional operator c ? t : f avoids ambiguity by the fact that neither the question mark nor the colon represent any dyadic operator, nor do they form part of any other operator.

So when you want a triadic infix operator, you are caught between either designing a careful system of naming which avoids reusing keywords/symbols for different operators, or designing a variety of special cases into the language which erode the generality of how operators can be composed into expressions.

The two horns of that dilemma are easily avoided by simply expecting the programmer to compose the range test from dyadic operators (e.g. (x >= y) AND (x <= z)), or by using the function-call notation (e.g. IsBetween(x, y, z)), and many language designers wouldn't have felt that more was needed.

4
  • The SQL operator BETWEEN is a bit of a pickle as it quite specific of testing between the two extrema not inclusive. InRange(x, l, u) with an optional boolean or an array of exactly two boolean stating enclusion of the extrema would indeed solve this.
    – theking2
    Mar 13, 2023 at 21:33
  • @theking2, actually it is inclusive in SQL. I've settled into being one of those people who prefers my ranges to be fully inclusive, and my indexes to start at 1!
    – Steve
    Mar 14, 2023 at 3:45
  • not if they are datetimess
    – theking2
    Mar 14, 2023 at 21:07
  • @theking2, indeed the behaviour with datetimes, when a range is specified by date only, is truly absurd.
    – Steve
    Mar 14, 2023 at 21:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.