views:

172

answers:

5

Hi all,

Just out of curiosity, asking this

Like the expression one below

a = (condition) ? x : y; // two outputs

why can't we have an operator for enums?
say,

myValue = f ??? fnApple() : fnMango() : fnOrange(); // no. of outputs specified in the enum definition

instead of switch statements (even though refactoring is possible)


enum Fruit
{
    apple,
    mango,
    orange      
};

Fruit f = Fruit.apple;

Or is it some kind of useless operator?

+2  A: 

C# borrows syntax from C++, and C++ borrows syntax from C, and C didn't have a ???::: operator, because K&R probably didn't feel like it was necessary. It's not a "useless operator", but it would be considered syntactic sugar.

Moreover, it's not a good idea for an operator to rely on the particular ordering of constants in the enum declaration.

Will
C and C++ not having the operator isn't a good reason in itself - they don't have lambda expressions or the null coalescing operator either. There are far better *other* reasons not to have it, such as the one in your last sentence. More importantly, there's no good reason *to* have it IMO.
Jon Skeet
A: 

condition is evaluated to true or false. What is proposed algorithm of your non-existing operator? It is difficult to say whether it may be useful or not, but switch-case can do what you need.

Alex Farber
i didn't understand your first question. can you rephrase it?
Veer
+15  A: 

I can't say I've ever wanted such an operator - which would be incredibly brittle by relying on the ordering of the enum values. You can easily use a switch:

switch (f)
{
    case Fruit.Apple: myValue = fnApple(); break;
    case Fruit.Mango: myValue = fnMango(); break;
    case Fruit.Orange: myValue = fnOrange(); break;
    default: throw new ArgumentOutOfRangeException("f");
}

Alternatively, create a map:

static readonly Dictionary<Fruit, Func<Foo>> FruitFunctions = 
    new Dictionary<Fruit, Func<Foo>> {
    { Fruit.Apple, fnApple },
    { Fruit.Mango, fnMango },
    { Fruit.Orange, fnOrange }
};
...

myValue = FruitFunctions[f]();

I've used both techniques in various situations, and far prefer them to the suggested operator, I'm afraid.

Jon Skeet
why can't we rely on their order?
Veer
@Veer you could add one later and then you would have to change all the places where you used the ??? operator. With the map you just need to modify it on one place.
Cornelius
@Veer: Two points - firstly, the order isn't visible at the point of use, so it becomes hard to read. Secondly, a seemingly innocent change in the enum declaration would completely change the meaning of the code.
Jon Skeet
Yes i would say mapping is a good idea. Even i've thought about it.If we're going to reorder the enum, it results in chaos. But how often would we reorder the enums. How oftern are we going to use this expression in our program?
Veer
@Veer: I'd say that when the defence of an operator being brittle or lacking in readability is "well you're not going to use it very often" then that says it all ;)
Jon Skeet
actually my primary defence is we are not going to reorder the enums often
Veer
@Veer: That doesn't make it any more readable, nor does it make it clear what's going to break if you *do* reorder the enums.
Jon Skeet
@Veer: when an operator is that brittle it is definitively a sign for C# team not to include it in the language. There is not high added value. On the contrary, one more way to shoot yourself in the foot.
Petar Repac
@Jon: can we use something like this: Dictionary<Func<Foo>, Fruit> (not related to this question anyways) so that the return value of the function could be used as a key?
Veer
@Veer: Well, I suppose you *could* write your own `IComparer<Func<Foo>>` which tested for equality and hash code by calling the function, but it would be very odd. It would make more sense to make it a `Dictionary<Foo, Fruit>` and call the function yourself.
Jon Skeet
I know the key has to be static. I wanted to know is there anything with which we could fetch the corresponding value according to the return value of a function.
Veer
@Jon: Oh thanks! thanks for the fast reply:)
Veer
+4  A: 

Offhand I can think of three reasons:

  1. It's brittle. If somebody decides to reorder the enum, then you'll end up with the wrong functions being called.
  2. It's non-obvious. I can't understand which function will run in which case without switching over to the enum definition and checking which order the enums are in.
  3. Every feature starts with minus 100 points. Something like this is unlikely to justify the effort required to spec, build, document and test it, especially when compared to other features, and especially especially when there's a highly viable alternative already in the language.
itowlson
A: 

The main problem - apart from it being unsafe, unnecessary, and probably unreadable in most real cases - is that it promotes a programming model that most people would these days regard as bad.

Most languages have programming/design styles they allow and those they want to promote. C# allows imperative and procedural programming but promotes the use of object oriented techniques. Your operator belongs firmly in the first camp and is not something that the designers of the language would want to support.

If you did want to program in that style then you could use:

    myValue = (f == Fruit.apple) ? fnApple() 
            : (f == Fruit.mango) ? fnMango()
            : fnOrange();
Dipstick