21

To summarize it quickly, why isn't 2 < x < 9 equal to 2 < x && x < 9?

This is the test code I've written:

#include <iostream>

int main()
{
    int nums[] = { 5 , 1, 10};

    // We are gonna check if the number is in the range 2 - 9 
    for (auto e : nums)
    {
        if (2 < e < 9)
            std::cout << "2 < " << e << " < 9" << std::endl;

        if(2 < e && e < 9)
            std::cout << "2 < " << e << " and " << e << " < 9" << std::endl;
    }

    std::cin.get();
} 

Here is the output I'm getting:

2 < 5 < 9
2 < 5 and 5 < 9
2 < 1 < 9
2 < 10 < 9

It looks like only 2 < e && e < 9 works correctly.

Boann
  • 48,794
  • 16
  • 117
  • 146
Marcin Poloczek
  • 923
  • 6
  • 21
  • 9
    Because e.g. `2 < 10 < 9` will be interpreted as `(2 < 10) < 9`, that is `1 < 9` which is true – Federico klez Culloca Jun 10 '19 at 12:20
  • 3
    Because the compiler is processing the operators from left to right and with precedence in mind. `2 < 10 < 9` is therefore processed as `(2 < 10) < 9`, from which we get `1 < 9` as 2 is less then 10 results into `true` which is interpreted as 1. – Anže Jun 10 '19 at 12:21
  • 5
    This notation makes a lot of sense in mathematical text but is hard to consistently capture with a parser, without confusing parsing rules. In particular, '>' would no longer be a binary operator that applies directly to its left hand and right hand neighbors, and parsers would have to look in a larger context window for meaning. – jwimberley Jun 10 '19 at 12:21
  • 13
    Nitpicking about terminology, in the upcoming C++20 standard there will come a [three-way comparison operator](https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison). But it doesn't do what you want either, so please be careful when using that term. – Some programmer dude Jun 10 '19 at 12:24
  • 6
    The only language I'm aware that has such a comparison is Python, where `a op1 b op2 c` is just syntactic sugar for `a op1 b and b op2 c`. (So Python also allows weird things like `2 < 3 != 1` (which is true) and `1 < 2 in [3,4,5]` (which is false).) – molbdnilo Jun 10 '19 at 12:32
  • 1
    If you need that kind of comparator you can always write your own, e.g. `template bool less3(T a, T b, T c) { return a < b && b < c; } /**/ if (less3(2, e, 9)) {...} /**/` – mcabreb Jun 10 '19 at 13:18
  • @mcabreb: You may as well use `std::clamp` if you want to go down that path. – Bathsheba Jun 10 '19 at 13:26
  • Possible duplicate of [Comparing a variable to a range of values](https://stackoverflow.com/q/3830644/608639). Also see [What is the <=> operator in C++?](https://stackoverflow.com/q/47466358/608639) – jww Jun 10 '19 at 21:06
  • @mcabreb: https://ideone.com/awrmK – Mooing Duck Jun 10 '19 at 21:18
  • 1
    And for a practical reason why few languages have such an operation, it's much easier to understand "(2 < x) && (x < 9)", especially if you use parens. And easier still to understand "(x >=2) && (x < 9)" :-) Why write unclear code when there's no obvious benefit? – jamesqf Jun 10 '19 at 22:21
  • 2
    A better name rather than "three-way comparison" (because of the [name clash](https://en.wikipedia.org/wiki/Three-way_comparison)) is "chained comparisons" – Justin Jun 10 '19 at 23:28
  • [Language support for chained comparison operators (x < y < z)](https://stackoverflow.com/q/4090845/995714), [Why do most mainstream languages not support “x < y < z” syntax for 3-way Boolean comparisons?](https://softwareengineering.stackexchange.com/q/316969/98103), [Is (4 > y > 1) a valid statement in C++? How do you evaluate it if so?](https://stackoverflow.com/q/8889522/995714) – phuclv Jul 14 '21 at 03:31

6 Answers6

36

The expression

2 < x < 9

is grouped as

(2 < x) < 9

And since 2 < x is either false (0) or true (1), and both are less than 9, it's always true.

So unless you use overloaded operators for a non-built-in type x (then a 3-way comparison would be possible if 2 < x were to return an instance of a proxy object on which < is defined), if you want to test if x is in the interval (2, 9) you need to write it the way you have.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
20

Just because this language doesn't have that feature.

It could have been made to, but this would contrast with C in a non-compatible way.

C could have been made to, but the designers simply didn't do that.

You already have the correct way to do it.

Some different (and newer!) languages do support this.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    If contrasting with C was an issue, all C code would be compilable with a C++ compiler, which is not the case. – Federico klez Culloca Jun 10 '19 at 12:24
  • 19
    @FedericoklezCulloca That's a bit of a fallacy. It is quite clear that the language designers have gone to great lengths to ensure a high level of compatibility with C. No, it's not a strict superset, but it's _really, really close_. Fundamentally changing the way operators work would be a big no-no. – Lightness Races in Orbit Jun 10 '19 at 12:25
  • 2
    @FedericoklezCulloca C++ was explcitly designed to be mostly backwards compatibile with C. Of course there are places it couldn't be, but for basic syntax rules like this, the C way was maintained. – NathanOliver Jun 10 '19 at 12:27
  • 1
    I doubt that any C programmer writes such code, because the result is nonsense. There was a proposal for this but it was rejected due to parsing issues in some compilers. – Rakete1111 Jun 10 '19 at 12:39
  • My favourite example: `&` and `&&`. Actually, it would have been much more comfortable in pure C++ if they opted for breaking the compatibility with C and had given the bitwise operator higher precedence than the comparison operators. This precedence as is dates back to the times the `&&` operator had not yet been invented in C. But if we drop this isolated view on C++, hell breaks loose faster than we even could ever measure... – Aconcagua Jun 10 '19 at 12:47
  • This would be a great answer if you removed the first line. "Just because..." makes it sound like you're saying there's no reason. Then you give the reason. – Apollys supports Monica Jun 10 '19 at 21:31
  • @Apollys It's transitive. "A, just because B. B, just because C!" – Lightness Races in Orbit Jun 10 '19 at 22:54
  • Sure, I'm not arguing with the logic, rather the presentation. Just letting you know I first read the answer and thought it was confusing and unhelpful. Then I came back and mentally removed the first line and found it quite straightforward and useful. – Apollys supports Monica Jun 19 '19 at 00:11
4

the comparison operators in c++ takes as an argument two values. when you are writing a<b it is the same as operator<(a,b). and the return value of operator< is bool. when you are calling a function in c++, it is computing the expression of its arguments and then passing it to that function, so calling a<b<c is same as operator<(operator<(a,b),c)

basically, the answer to your question is that in c++ there is no comparison operator (less than, greater than...) that takes three arguments

zapredelom
  • 1,009
  • 1
  • 11
  • 28
3

If C++ chose to redefine a < b < c to better align with the mathematical notation, it would be ambiguous with the current meaning. The current meaning is a bit silly and is comparing bools with numbers, but there may be tricky code relying on this detail in production use.

And as C++ allows you to define your own types with operators, it would have to expose the new ternary < to you as well, so you could make one for your type. Which would open new cans of worms if you only define a binary < but no ternary < for your type - should the compiler start shouting at you?

  • 2
    *"your own types with operators, it would have to expose the new ternary < to you as well"* - you can orchestrate `a < b < c` for your own type quite easily with the existing C++ language: you just have `a < b` return a helper object (of a different type) that stores the `bool` result AND the value of `b` AND provides an `operator bool() const` for when just `a < b` is used, but if that helper object is compared with something else and the stored `b` is not `< c` it sets its `bool` member to false. So, the show-stopper is exclusively with being unable to implement it for *built in* types. – Tony Delroy Jun 10 '19 at 12:51
  • 3
    You can. But if you ever feel the desire to actually do this, have a cold shower and wait for it to pass. –  Jun 10 '19 at 12:57
  • By all means argue that if you like - I'm just pointing out that your current answer is wrong in saying some new ternary `<` would *need* to be exposed for use by user-defined types. (Though it may still make sense to expose a dedicated operator for efficiency reasons.) – Tony Delroy Jun 10 '19 at 13:04
  • @TonyDelroy is it? OP is arguing that the behavior should be changed for a built-in type (int), introducing a new ternary `<`, I am saying that that change should propagate to user-defined types. –  Jun 10 '19 at 13:11
  • If that makes sense to you, leave you answer as is. Cheers. – Tony Delroy Jun 10 '19 at 14:02
3

C++ didn’t do it because that would have broken backward compatibility with C. So you would need to look another decade back for the answer.

I don’t know whether Brian Kernighan or Dennis Ritchie ever considered doing it the other way, or discussed their reasoning. I’m not aware of anyone requesting that specific feature. Their relational operators follow the same rules as other Algol-family languages.

One problem would have been that it makes the grammar ambiguous: 0 < x < 1 now has a very different meaning than (0 < x) < 1 or 0 < (x < 1). There are also the issue of how to parse a < b >= c or a < b == c. Remember, there was no Boolean type in K&R C. Logical operators returned int, since the result was presumed to be stored in a machine register.

Another possible reason behind it is that K&R C, according to its designers, is not a high-level language. Its basic operations generally correspond to machine instructions on the minicomputers it was developed on. So, a comparison was a machine instruction back then, and a double-comparison was not. It would’ve been strange, given the other choices they made, to introduce that particular syntactic sugar into the language just to make C code read a little more like a math paper.

Davislor
  • 14,674
  • 2
  • 34
  • 49
1

Inside of if, there should be boolean condition. In 2 < x < 9, there are two conditions. And two conditions can't be calculated in C++ without operator between them. That's why we can't use 2 < x < 9.

Faruk Hossain
  • 1,205
  • 5
  • 12