The type of the expression a == be 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 == be == c is parsed as (== a be 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.
The type of the expression a == be 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 == be == c is parsed as (== a be 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.
Well, the expression c == 2 would return true, so then be 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.
Relational operators, OTOH, can actually make sense. This is something I always support in my languages; it's not hard at all. – Stephen Cleary Jun 9 '10 at 15:35 1 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 Jun 9 '10 at 15:36.
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 blog.ryjones.org/2005/07/12/product-deve..." rel="nofollow">blog.ryjones.org/2005/07/12/product-deve... and blog.ryjones.org/2005/07/12/product-deve..." rel="nofollow">blog.ryjones.org/2005/07/12/product-deve... 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: stackoverflow.com/questions/797014/does-... something new has be be very useful to make it into the language.
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 == be == c different from (a == b) == c in certain situations?
What if I really want to compare c to the Boolean result of a == be 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 Equals(b, c, d, e, f, g)) { // ... }.
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.
I think you're question somewhat deteriorates at your point of reference. There's nothing magic about a = be = c = 2 to suggest that a == be == 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 == be == 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 == be == 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 && be == 2 really that bad?
;).
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 = be = c = 2 and have them all assigned the value 2. Otherwise, you'd end up with a having the old value of be and be 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 == be or a && be evaluates a first. You could argue that == could be right-associative... except that in . NET it can't, because for objects, a == be is (unless overridden) converted to a.
Equals(b) (or is that a. ReferenceEquals(b)... I never remember).
Not a direct answer to your question, but how about: bool allTwo = a & be & c == 2; EDIT: As Pete says, that wouldn't work. How's this? Bool allEqual(params int inputs) { int lastval = inputs0; for (int I = 1; I Length; i++) { if (lastval!
= inputsi) return false; lastval = inputsi; } 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 == be && be == c && c == 2; // prefer this format over a == 2 && be == 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.
So far, so good: expr1 represents the integer constant 42, expr2 and expr3 the boolean constants True and False. All values of type Expr with Con as their outermost constructor essentially look like this. Expr4 and expr5 are fine; they represent the expressions True && True and True && (False && False), respectively.
We would expect them to evaluate to True and False, but more on that soon. However, expr6 looks fishy: it represents the expression True && 42 which doesn't make sense (in Haskell, at least!). The expressions we have seen so far, except number 6, all have a value: expr1 has the integer value 42, the rest are booleans (True, False, True, False for exprs 2 through 5).
As you can see, the values are either integers or booleans and so can be represented as values of type Value. We can write an evaluator which takes an Expr and returns its Value. In words, the evaluator should return the value of a constant expression and if the expression is a logical 'and', it should return the logical 'and' of the values of constituent expressions, which need to be boolean values - you can't take the logical and of an integer and a boolean, or two integers.
This is just a more verbose version of the first est, with the operation of taking the logical 'and' of two evaluated expressions spun off into a separate function and slightly more informative error messages. Okay, hopefully this answers your first question! The problem boils down to the fact that Expr values can either have a boolean or an integer value, and you can't "see" that type anymore, so it's possible to And two expressions together for which this doesn't make sense.
One way to solve this would be to split Expr into two new expression types, one having integer values and the other with boolean values. Two things are interesting to note: we've gotten rid of the Value type, and now it's become impossible to construct the equivalent of expr6 - this is because its obvious translation AndBool (ConBool True) (ConInt 42) will be rejected by the compiler (it might be worth trying this out), because of a type error: ConInt 42 is of type IntExpr and you can't use that as the second argument to AndBool. The evaluator would also need two versions, one for integer expressions and one for boolean expressions; let's write them!
This is where GADTs come in! Instead of making a separate type of expression for each possible resulttype of the evaluation (IntExpr and BoolExpr above), we are going to "tag" the expression type itself with the type it will evaluate to.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.