tags:

views:

1153

answers:

4

Are there any good solutions to represent a parameterized enum in C# 3.0? I am looking for something like OCaml or haXe has. I can only think of class hierarchy with a simple enum field for easy switching for now, maybe there are better ideas?

See Ocaml example below in one of the replies, a haXe code follows:

enum Tree {
   Node(left: Tree, right: Tree);
   Leaf(val: Int);
}
A: 

C# (the .NET framework in general, as far as I know) doesn't support parametrized enums like Java does. That being said, you might want to look at Attributes. Some of the features that Java enums are capable of are somewhat doable through Attributes.

MagicKat
Well correct me if I am wrong but I think Java enums allow for parameters - but same for all enum constructs, not a unique parameter list per construct like OCaml does. I need the ocaml way, so Attributes are not of much help here - but thanks anyway!
Michael Pliskin
A: 

Whats wrong with just using a class for this? Its ugly, but thats how the Java people did it until they had language integrated Enum support.

FlySwat
The problem with classes is that it's difficult to switch over them then. Given an enum value, I'd like a quick'n'easy way to understand what it is and what are it's arguments. I can do that with a class hierarchy and simple enum switch, but this doesn't sound too elegant..
Michael Pliskin
+6  A: 

Not being familiar with ocaml or haxe, and not being clever enough to understand the other explanations, I went and looked up the haxe enum documentation - the 'Enum Type Parameters' bit at the bottom seems to be the relevant part.

My understanding based on that is as follows:

A 'normal' enum is basically a value which is restricted to the things that you have defined in your enum definition. C# Example:

enum Color{ Red, Green, Yellow, Blue };
Color c = Color.Red;

c can either be Red, Green, Yellow, or Blue, but nothing else.

In haxe, you can add complex types to enums, Contrived example from their page:

enum Cell<T>{ 
  empty; 
  cons( item : T, next : Cell<T> )
}

Cell<int> c = <I don't know>;

What this appears to mean is that c is restricted to either being the literal value empty (like our old fashioned C# enums), or it can also be a complex type cons(item, next), where item is a T and next is a Cell<T>.

Not having ever used this it looks like it is probably generating some anonymous types (like how the C# compiler does when you do new { Name='Joe'}.
Whenever you 'access' the enum value, you have to declare item and next when you do so, and it looks like they get bound to temporary local variables.

Haxe example - You can see 'next' being used as a temporary local variable to pull data out of the anonymous cons structure:

switch( c ) {
  case empty : 0;
  case cons(item,next): 1 + cell_length(next);
}

To be honest, this blew my mind when I 'clicked' onto what it seemed to be doing. It seems incredibly powerful, and I can see why you'd be looking for a similar feature in C#.

C# enums are pretty much the same as C/++ enums from which they were originally copied. It's basically a nice way of saying #define Red 1 so the compiler can do comparisons and storage with integers instead of strings when you are passing Color objects around.

My stab at doing this in C# would be to use generics and interfaces. Something like this:

public interface ICell<T> {
   T Item{ get; set; }
   ICell<T>{ get; set; }
}

class Cons<T> : ICell<T> {
  public T Item{ get; set; } /* C#3 auto-backed property */
  public Cell<T> Next{ get; set; }
}

class EmptyCell<T> : ICell<T>{
  public T Item{ get{ return default(T); set{ /* do nothing */ }; }
  public ICell<T> Next{ get{ return null }; set{ /* do nothing */; }
}

Then you could have a List<ICell<T>> which would contain items and next cell, and you could insert EmptyCell at the end (or just have the Next reference explicitly set to null). The advantages would be that because EmptyCell contains no member variables, it wouldn't require any storage space (like the empty in haxe), whereas a Cons cell would.
The compiler may also inline / optimize out the methods in EmptyCell as they do nothing, so there may be a speed increase over just having a Cons with it's member data set to null.

I don't really know. I'd welcome any other possible solutions as I'm not particularly proud of my one :-)

Orion Edwards
Thanks, that's what I was actually thinking of, but you provided a very detailed explanation how it could be done! And yes probably nothing better...
Michael Pliskin
A: 

Use a class that with static properties to represent the enumeration values. You can, optionally, use a private constructor to force all references to the class to go through a static property.

Take a look at the System.Drawing.Color class. It uses this approach.