views:

211

answers:

8

Given that it's valid to write

a = b = c = 2;

It would also be nice, rather than

bool allTwo = a == 2 && b == 2 && c == 2;

to instead write

bool allTwo = a == b == c == 2;

But I can't since a == b evaluates to a boolean which can't then be compared to an integer.

Is there a language-design reason it has been implemented this way?

+4  A: 

Well, the expression c == 2 would return true, so then b would be being compared to true rather than 2.

Edit: It was most likely implemented this way as that's how C-style languages handle boolean expressions. They'd have to make a special exception for multiple terms and implement it differently whereas with the assignment operator it's more straightforward: the right most expression evaluates to a value that can logically be applied to the next expression in the chain. Seems the designers took the simple approach.

Bob
Relational operators, OTOH, can actually make sense. This is something [I always support](http://nitoprograms.blogspot.com/2009/09/minor-improvements-for-language-design.html) in my languages; it's not hard at all.
Stephen Cleary
Yes but this is only the case because that's how it's been implemented. I'm asking why it has been implemented that way.
Ed Guiness
A: 

Not a direct answer to your question, but how about:

bool allTwo = a & b & c == 2;

EDIT: As Pete says, that wouldn't work. How's this?

bool allEqual(params int[] inputs)
{
    int lastval = inputs[0];
    for (int i = 1; i < inputs.length; i++)
    {
        if (lastval != inputs[i])
            return false;

        lastval = inputs[i];
    }

    return true;
}

Declare it once, use it whenever you want with a comma-separated list of integers to compare. (There's probably an even simpler function for it, but whatever.)

bool allTwo = a == b && b == c && c == 2; // prefer this format over a == 2 && b == 2 && c == 2, personally

versus

bool allTwo = allEqual(a, b, c, 2);

There's not really much for me to say in regards to your question itself that hasn't already been said in the answers of others.

JAB
Pete Kirkham
+6  A: 

The type of the expression a == b is boolean, so you would either have to break a rule that an expression means the same thing whatever its context, or have n-ary == operators so that a == b == c is parsed as (== a b c) rather than (== (== a b) c). Which then means you need to have (a == b) == c to compare the boolean c to the result of (a == b), which is OK, but not the simple C style of grammar which C# is in the tradition of.

Pete Kirkham
+1  A: 

To do what you want, operator == should return object. In this case, we will have another problem - now we need an implicit conversion of any object to boolean. Such a conversion will also create extra problems.

a1ex07
+2  A: 

I can't find the quote, but I think it was Eric Lippert (?) who put it best: not implementing a feature is free. See also http://blog.ryjones.org/2005/07/12/product-development/ and http://blog.ryjones.org/2005/07/12/product-development/

They have many features to implement and I can't imagine something non-standard like this with questionable value would be a high priority. I'm not saying it's not valuable, but it could lead to confusion, probably wouldn't be used very often, etc. I think a1ex07 has a good point too. This would have to be a custom case since it can't really be handled generically anymore (== always returns boolean, etc.)

You can do the same thing now with LINQ, but the syntax is a bit more convoluted and it requires allocating an array of some sort:

bool allTwo = new int[] { a, b, c }.All(i => i == 2);

You can do it backwards and check if any != 2:

bool allNotTwo = new int[] { a, b, c }.Any(i => i != 2);

In both of these cases it will also quit as soon as one is invalid, so you often won't go through the whole list.

Edit: Here's another point: http://stackoverflow.com/questions/797014/does-c-have-too-many-language-features

something new has be be very useful to make it into the language

Nelson
+1  A: 

I think you're question somewhat deteriorates at your point of reference.

There's nothing magic about a = b = c = 2 to suggest that a == b == c == 2 should work like you're wanting -- actually more-so the opposite.

The assignment operator is defined for only 2 operands and returns the value being set. A string of them simply passes the value from each operator to the next:

1: a = (b = (c = 2));
2: a = (b = (2));
3: a = (2);

So, the same is true for a == b == c == 2:

1: bool allTwo = (a == (b == (c == 2)));
2: bool allTwo = (a == (b == ([Boolean])));
3: bool allTwo = (a == ([Boolean]));
4: bool allTwo = ([Boolean]);

So, the technical reason is simply that C# doesn't contain a definition to have special treatment for a string of operators.

As for language design and implementation, the reason would probably be to prevent ambiguity and additional complexity. While you may want a == b == c == 2 defined as an all equal operator now, on the next line you may very well need it to act as currently implemented. How should the behaviors be distinguished? And would it be truly worth the effort to implement?

Or is a == 2 && b == 2 really that bad? ;)

Jonathan Lonowski
+2  A: 

From my perspective it's a question of clarity. If the decision were up to me, I would consider how adding such a language feature might add too much ambiguity regarding how complicated expressions are evaluated. Is a == b == c different from (a == b) == c in certain situations? What if I really want to compare c to the Boolean result of a == b rather than compare c to b? In most cases the compiler can probably figure out the proper comparison, but if c is implicitly convertible to bool, though unlikely, then it might be impossible to tell.

So personally, I'm not sure it's worth the hassle. While it may not look as nice syntactically, you could build your own utility function to compare equality of multiple objects, such as below:

    public static bool Equals(this object x, params object[] y)
    {
        for (int i = 0; i < y.Length; i++)
        {
            if (!object.Equals(x, y[i]))
                return false;
        }
        return true;
    }

Then you could use it like this:

        if (a.Equals(b, c, d, e, f, g))
        {
            // ...
        }
Dr. Wily's Apprentice
+1  A: 

Ignoring return values, it also has to do with operator associativity.

Assignment operators are right-associative. That is to say that the right side of an assignment operator is evaluated first. This is why you can do a = b = c = 2 and have them all assigned the value 2. Otherwise, you'd end up with a having the old value of b and b having the old value of c.

Most other operators are left-associative, particularly the short-circuit logic operators (&& and ||). That is to say that a == b or a && b evaluates a first.

You could argue that == could be right-associative... except that in .NET it can't, because for objects, a == b is (unless overridden) converted to a.Equals(b) (or is that a.ReferenceEquals(b)... I never remember).

R. Bemrose