views:

130

answers:

3

Is there a programming language that supports chained notation a < b < c to be used instead of a < b and b < c in conditional statements?

Example:

  1. if ( 2 < x < 5 )
  2. if ( 2 < x && x < 5 )

First statementlooks better to me, it's easier to understand and the compiler could use transitivity property to warn about mistakes (e.g. 5 < x < 2 would give a warning).

+4  A: 

Python does that.

Martinho Fernandes
+2  A: 

This sounds like a simple request (and clearly it is simple enough that python implemented it) but it is not necessarily that easy to use. It actually opens up the ability for a lot of errors to be caused.

Specifically, any time that you use functions (or properties in the case of C#, Getters for Java)

So

public int GetX()
{
   return 4;
}

(2 < GetX() < 5);

(2 < GetX() > 5);

(5 < GetX() < 2);

Seems like it would be really simple. But problems occur if GetX() has side effects.

private int val = 10;

public int GetCountdown()
{
   return val--;
}

(2 < GetCountdown() < 5);

(2 < GetCountdown() > 5);

(5 < GetCountdown() < 2);

In this situation, is "GetCountdown()" decremented twice or just once? Would the "chained-if-statement" ever shortcut?

Consider the last statments, which roughly evaluates (in english) to "Is 5 less than some value which is less than 2) which should be impossible, but depending on the implementation and side effects, it is possible that some function (Random.NextInt()) could pass both of those tests.

So, for that reason, it would be required that each of the items is only evaluated once, the saved into a local variable for the next comparison. But then you get into shortcutting problems.

public int GetOne()
{
   return 1;
}

public int GetVar()
{
   return -1;
}

(GetOne() < GetVar() < GetDBVal() < GetUserInput())

Generally, you would want to first check constants and variables before doing a database hit. But if we said (as we said earlier) that all the values must be saved into local variables ahead of time, this means that it might be calling a database hit, and asking the user for information even though "GetVar()" is -1, and so the first comparison fails)

As I said earlier, clearly Python allows this syntax, so it is clearly possible. But, regardless of the technical implications which I have laid out (all of which are easy to design around) it means that your code is less clear because the next person who reads it does not know whether or not you have considered all of this. Whereas, if(x > 2 && x < 5) { } seems clear to me, I know what it does, and I know what the coder intends.

A good argument against functions with side effects.
High Performance Mark
Well, "GetDataFromDB()" wouldn't have a 'side-effect' per se, except that it would take time that would be best avoided. The purpose of this was just to illustrate that chaining comparisons could _itself_ have unintended consequences because it is not as clear as atomic comparisons.
The lesson to take from this is to always use functions with side-effects (I consider GetDataFromDB() to have a side-effect: it touches the external world) as **statements**. Use only side-effect free code as **expressions**.
Martinho Fernandes
But that's coding _practice_. Users could still misuse this. Ideally, a language should be both easy and intuitive to use for the maximum number of people while simultaneously being easy to read and understand for everyone else. It should also be built to discourage or highlight bad practices. In this case, bad practices can be more easily hidden and obscured by the syntax.
As well, the compiler error that is provided when you attempt this clarifies the intent of the language designers. "Error: Operator '<' cannot be applied to types `bool` and `int`" The '<' operator has a value (provides) that is boolean, and the types on either side must match. As soon as you allow chaining, that is no longer true, because the statement `a < b < c < d` can no longer be coalesced into valid statements.
Sure, this is a construct that can be easily abused. I was just pointing what the "non-bad" practice should be.
Martinho Fernandes
hey, with great power comes great responsibility ;)
Davorin
@Martinho I agree completely, @Davorin In this case, the argument comes up with 'gain vs. risk' the gain would be minimal, because you would only be adding syntactic sugar, and I've highlighted the risks. But, who knows, maybe C# 4.5 will have it.
+5  A: 

Icon does this, and it is not part of any hacky special-case "chaining"; it is part of Icon's goal-directed evaluation model. Any comparison either succeeds or fails. If it succeeds, it produces the right-hand side. So you can write

if 0 <= i <= j < n then ...

and it works exactly the way you would expect. But it works not just for comparisons but for any expression; this means you can write your own functions that "chain" in exactly the same way. I love this aspect of Icon and wish more languages could incorporate goal-directed evaluation.

N.B. In Guido's paper introducing Python at VHLL (middle 1990s) he mentions Icon explicitly as a source of inspiration in the design of Python.

Norman Ramsey
Oooh.... shiny.
outis