37

The Python language has a neat feature: An expression like x < y <= z is interpreted, according to mathematical convention, as equivalent to x < y and y <= z. Operands are evaluated only as many times as they appear, and the short-circuiting nature of the equivalent operation is maintained. For example,

if f() <= g() < h() <= i(): whatever

behaves as if the code were

x1 = f()
x2 = g()
if x1 <= x2:
  x3 = h()
  if x2 < x3:
    x4 = i()
    if x3 <= x4:
      whatever

(Thus h() and i() aren't evaluated unless necessary.)

As far as I am aware, the first language to support this was CPL, as demonstrated on page 6.1.3 of the CPL working papers. However, CPL was never implemented fully, so it could be argued that the feature was never supported, per se. Were there earlier examples?

34
  • 23
    As another-dave said, just because Python (or Cobol) implemented it doesn't mean they should have done. It's a bug factory in non-trivial situations
    – alephzero
    Jun 23, 2021 at 12:50
  • 19
    I bet you've never written an in-fix expression parser. A parser that knows that a < b < c means something entirely different from (a < b) < c or a < (b < c) will be more complicated—harder to write, harder to understand—than the parsers used in other programming languages. And, if it's harder for a program to parse the expression, then it's harder for a human to understand it too. Of course, once you've learned what it means, then it's easy enough to see, but before you could "see" it you had to learn one extra thing about Python expressions than you didn't learn for other languages. Jun 23, 2021 at 14:07
  • 5
    @Solomon By that argument the grammar for say MIPS assembly is far easier to parse than that of any more complicated programming language (you don't even have to worry about ifs! just comparisons and jumps, great!). Hence by your argument it means that assembly is the easiest possible language for a human to understand.
    – Voo
    Jun 23, 2021 at 16:50
  • 17
    @SolomonSlow I don't agree it's "one extra thing" you have to learn. In fact (from experience of teaching this) it's the opposite: it's what learners trying to write this code in other languages do before they learn how to do it the other, less intuitive, way. Jun 23, 2021 at 16:52
  • 13
    @Voo, Good point. A Python program actually is much harder to understand than an assembly language program if your goal is to understand what it's going to instruct the hardware to do. But, the Python code is much easier to understand if your goal is to understand it at the level of the problem domain. I will have to think on this. Jun 23, 2021 at 17:02

3 Answers 3

59

COBOL

IF X IS GREATER THAN 0 AND LESS THAN 99 ...
10
  • 49
    EXCELLENT ANSWER
    – DrSheldon
    Jun 23, 2021 at 14:26
  • 3
    @wizzwizz4 you've obviously never used COBOL. (It's a great language for record processing.)
    – RonJohn
    Jun 23, 2021 at 18:44
  • 2
    Just curious, does COBOL support short-circuiting? Could you express, using whatever convention for subroutine calls, an analog of IF X IS GREATER THAN F() AND LESS THAN G() in a way to guarantee that G() is called only if X > F()?
    – Leo B.
    Jun 24, 2021 at 3:13
  • 5
    Enterprise COBOL 6.3 seems to be always short-circuiting according to the Language Reference: "The constituent connected conditions within a hierarchical level are evaluated in order from left to right, and evaluation of that hierarchical level terminates as soon as a truth value for it is determined, regardless of whether all the constituent connected conditions within that hierarchical level have been evaluated."
    – piet.t
    Jun 24, 2021 at 7:14
  • 1
    @Dai. You can add parenthesis if you want: c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z')
    – md2perpe
    Jun 24, 2021 at 13:41
5

It's also available in BCPL: see section 5.2 of the 1967 reference manual which unlike CPL was implemented and used very widely.

The semantics are described very concisely: each of the relations between pairwise operands must be true, so A < B > C means (A < B and B > C), except that B (one assumes) is only evaluated once.

I also found a 1974 version of the reference manual in which it is stated that the number of times B is evaluated is implementation-defined.

1
0

Lisp:

(if (<= (< (<= (f) (g)) (h)) (i)) whatever)

Everything old is new again...

1
  • 6
    That won't work in any Lisp dialect I know of, unless you've defined > and >= to be macros. On the other hand, (> a b c d) is perfectly valid in Common Lisp, and you could consider it to be a form of chaining. In any case, all Lisp dialects in existence when COBOL was created allowed the arithmetic predicates to accept only two arguments.
    – texdr.aft
    Jun 25, 2021 at 19:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .