Hi Jon,
Both Enum and ValueType are classes, in fact.
True, but I was referring to what VS.NET shows. It seems to always shows "struct" for value-types instead of "class" in the
intellisense, except on Enum. Not really imporant, just something I noticed.
Not necessarily. If I have a rich enum with several data members, it's
cheaper to pass a reference by value than to pass all those members.
Just making the type immutable is fine, in the same way that string is.
Cheaper, yes, but then your Type doesn't necessarily replace Enum. I think if you are going to extend an Enum's behavior by
creating a custom Type then your Type should also preserve the in-memory behavior of Enum, otherwise you're not really replacing
Enum your just creating a class that encapsulates the functionality that you desire, with a chosen set of functionality that
parallels that of Enum. I see them as two distinct entities if you're not preserving all of the functionality provided by Enum, and
not a replacement.
I think a lot of the concerns are off-base though. Yes, you could make
mistakes like making the enums mutable without thinking things
through, but that's the kind of mistake that can be made in a lot of places.
But that mistake won't be made if you aren't trying to reproduce functionality that is already provided to you by a primitive Type.
If your propsed extension existed in the framework now then things would be different.
The fundamental concept of having an enumerated set of values is
completely separate from whether the type should be a value type or a
reference type, IMO.
I disagree. I believe how the Type behaves in memory is very important. Enums are always passed as a value, and therefore a
base-type that will replace it must do the same otherwise it's not really a replacement, IMO.
Well, not really a primitive, but it certainly exists in the framework
as a first-class citizen.
I'll take your word for it because I really don't know.
But maybe that's because the real primtives aren't base types like Enum. For instance, having TypeCode.Enum might not be very
useful, which is why it doesn't exist, but it doesn't mean that the framework doesn't provide "primtive" support for Enum at
runtime. After all, there is an "IsEnum" property on the Type class. I guess I'd have to define what "primitive support" actually
means in terms of the compiler and CLR, however I just can't do that because I'm really no expert on that subject
(The point is that it's provided, intrinsically. Whether or not it's deemed as a true "primitive" doesn't affect my point.)
However, .NET enums *don't* provide all the desired functionality, a
lot of the time. Many times you see switch statements handling enums,
where if you could embed the logic (or whatever the switch is doing)
within the enum as a polymorphic method, the code would be a lot
clearer. I don't see what's wrong with making the leap to that more OO
way of doing things, even without the runtime supporting it in a
first- class manner.
But in the current framework your describing something that would no longer be an Enum. You're describing a class that provides
more functionality than Enum provides. I'm not against that in any way, and would recommend it over using custom Attributes on an
Enum, for example. If there was a base type, such as the one you've proposed, I'm sure I'd use it in places where it was
appropriate. I'm sure there would be an equal number of, if not more, places where Enum would still be appropriate. Not every Enum
requires additional behavior or state (I assume that most wouldn't benefit from that ability at all). Therefore, Enum doesn't need
to be completely replaced as Steven suggested in his OP.
Enums provide a certain amount of functionality, yes - but a lot of
the time there's other functionality (particularly the ability to
store extra, rich data and to act polymorphically) which is much more
important to me than a lot of the functionality that enums *do*
provide.
I agree that there may be times where you need more than what Enum provides while trading off existing functionality provided by
Enum because it's not needed. If your propsed extension existed now, then it would no longer be a custom Type, it would be
primitive (or first-class citizen

. Steven's example is a custom Type and definately does not replace the Enum Type. They are
two different animals as I see it.
I haven't done much .NET coding in anger since discovering how useful
Java classes are - and not since seeing some reasonably elegant ways
of impersonating the design in C#. I can say that trying to produce
designs in .NET which mirror the equivalent Java enums by using a C#
enum and help classes has led to much nastier code in the C# side, in
my experience.
I have to admit you're making me sad saying that C# is nastier than Java. We're not going to lose you in the community any time
soon, I hope?

.
I'm not a Java programmer so I can't concur - I'll just have to take your word on that.
My point was that you really can't (or shouldn't rather) replace Enum.
That makes sense *if* you really need the FlagsAttribute in a
particular scenario - but it doesn't make sense to insist that the
support is present in cases where you're not going to use it anyway. I
very rarely use FlagsAttribute, myself.
I completely agree. Again, Steven asked why he should use standard Enums at all. FlagsAttribute, IMO, was a good reason to use
Enums since they already provide that support. If he needs more than what Enum has to offer, he really doesn't have much of a
choice but to create a custom class now, but it's not going to replace Enum.
And that loses you a lot - that's what I'm saying. By insisting that
enums are "good enough" you lose a lot of powerful OO design
possibilities.
But just like your saying that FlagsAttribute isn't always necessary, I think OO Enums aren't always necessary either. I'm
perfectly content with the TypeCode Enum, for instance, as it stands in the current framework now. What more state or behavior
could be extended to TypeCode? What about FileAccess or BindingFlags for example? If you were to add any additional state or
behavior on these Enums it seems to me that the classes that actually use these enums and encapsulate the functionality associated
with them would then share functionality with another Type in the framework, breaking encapsulation.
I'm not sure I see your point.
I understood your question as meaning, "Why shouldn't the Enum type be able to store state information if your custom types can? On
the contrary, are your custom types limited in the amount of data they hold just like Enum is?"
My answer is simply that my classes aren't trying to provide the functionality that the Enum type does right now, and that Enum does
provide its functionality with the limitations that are present in the current framework. My types, therefore, cannot be compared
like this to the Enum class because they provide a different set of functionality that does require holding a variable amount of
state. It's like comparing apples and oranges, as I see it.
Why are you against the idea of enabling a pleasant design even in the
slightly limited form which is currently available? Yes, there are
times when the present enums are sufficient - but where they aren't, I
think it's highly commendable to strive for a more OO solution than to
settle for an enum and a helper class.
I'm actually for it. I read your article, as I stated, to help clear things up about the pattern as well. What I'm against is
trying to replace Enum type using a custom type in the current framework. I believe that's what this thread is about and I've tried
to prove why I think enum is useful. Sure, Steven can rewrite the functionality he needs from Enum everytime he needs to addorn it
with additional state or behavior, but he's by no means replacing the Enum type by doing so.
I don't see why being a value type makes the type safety any less
important. It's just as inappropriate to use a FontStyle as if it were
a FileAccess as it would be to use a String as if it were a Socket.
FontStyle style = FontStyle.Bold; // BTW, FlagsAttribute

FileAccess fa = (FileAccess) style;
I think it's a bit rediculous to assume that the lack of type-safety in Enum is at fault for code like the above. Sure, if it was
completely type-safe then you couldn't do that but a developer could just as easily use a static Parse method instead if they are
going to explicitly cast one type to another anyway. And if you pass around FontStyle as Int32 instead, and eventually cast it into
FileAccess then you're just asking for trouble. If you have an Enum value, pass it around and use it as an Enum and it will be
type-safe. Enum's are type-safe in every other aspect since the compiler will ensure that method parameters of a particular type of
Enum, for example, may only be passed instances of that Type (and at least it requires an explicit cast otherwise).
The reason why Enum being a value type is very important is because in some cases you may only have the "value" and not the "Type",
from say an unmanaged program for example. From a web service method perhaps, or maybe from a parsed flat-file. In these cases
it's the value that's important and this design becomes more like a "feature" than a "bug"

It's nice to be able to explicitly
cast an int into an Enum value instead of calling some parse method (or not being able to at all in a poorly written class that
implements the pattern you speak of).
And anyway, I use Enum.IsDefined / InvalidEnumArgumentException in properties that set an Enum value and methods that accept an Enum
argument, unless of course the Enum is [Flags] or I can be certain by flow of control that my program will never supply anything but
an appropriate value.
Overall, I was trying to address Steven's question, "And it got me to thinking... why should I EVER use standard enums?"
- Because you may only need a subset or exactly what Enum provides, but no more. I think Enum is much more general-purpose and
common than the pattern that you have brought to our attention.
As a side note, a state machine would work well if you needed to relate several additional constants to one enum value and/or add
behavior that is dependant on each constant, but the pattern that Steve used in his example works just fine too. I don't recommend
using custom Attributes on Enum constants to provide this functionality, however, and I've seen some talk about that in this thread.
That seems like a bad idea to me.