So I was needing some extra power from my enums and implemented the
typesafe enum pattern.
And it got me to thinking... why should I EVER use standard enums?
There's now a nice little code snippet that I wrote today that gives me
an instant implementation of the pattern. I could easily just always
use such an implementation instead of a standard enum, so I wanted to
know what you experts all thought.
Is there a case for standard enums?
I also noticed its very hard to find good examples of what can be
achieved with the pattern in a .NET context. Do a google for (
"typesafe enum pattern" -java ) and you don't get very many results!
Opinions? 34 11019
C# enumerations *are* type-safe. There is no such thing as a non-type-safe
enumeration. In C#, enumerations are inherited from the value type
System.Enum, which is a structure. There can be no confusion of enumeration
members and their integral counterparts without an explicit cast.
As for your difficulty in Googling the subject, try leaving off the word
"pattern" (i.e. "typesafe enum"). Of course, all references you find will be
related to the Java programming language because, as I said, C# enumerations
*are* type-safe.
--
HTH,
Kevin Spencer
Microsoft MVP
Software Composer http://unclechutney.blogspot.com
A watched clock never boils.
"Steven Nagy" <le*********@hotmail.comwrote in message
news:11**********************@i3g2000cwc.googlegro ups.com...
So I was needing some extra power from my enums and implemented the
typesafe enum pattern.
And it got me to thinking... why should I EVER use standard enums?
There's now a nice little code snippet that I wrote today that gives me
an instant implementation of the pattern. I could easily just always
use such an implementation instead of a standard enum, so I wanted to
know what you experts all thought.
Is there a case for standard enums?
I also noticed its very hard to find good examples of what can be
achieved with the pattern in a .NET context. Do a google for (
"typesafe enum pattern" -java ) and you don't get very many results!
Opinions?
I somehow found that there is quite an amount of enum write out in C#
specification which is quite good: http://msdn.microsoft.com/netframewo...r/default.aspx
chanmm
"Steven Nagy" <le*********@hotmail.comwrote in message
news:11**********************@i3g2000cwc.googlegro ups.com...
So I was needing some extra power from my enums and implemented the
typesafe enum pattern.
And it got me to thinking... why should I EVER use standard enums?
There's now a nice little code snippet that I wrote today that gives me
an instant implementation of the pattern. I could easily just always
use such an implementation instead of a standard enum, so I wanted to
know what you experts all thought.
Is there a case for standard enums?
I also noticed its very hard to find good examples of what can be
achieved with the pattern in a .NET context. Do a google for (
"typesafe enum pattern" -java ) and you don't get very many results!
Opinions?
Thanks Kevin.
Yes I know enums are type-safe. I was more interested in the actual
pattern.
Its not the aspect of being type-safe that my question relates to, and
I suppose in that context my question could have been misleading.
The pattern is based around providing a class instead of an enum and
thus realising more potential as a class than an enum could. My
interest is around that, and what people have found to be useful about
the pattern, or perhaps what people have discovered that a standard
enum provides that an implementation of the pattern could not.
Thanks,
Steven
Kevin Spencer wrote:
C# enumerations *are* type-safe. There is no such thing as a non-type-safe
enumeration. In C#, enumerations are inherited from the value type
System.Enum, which is a structure. There can be no confusion of enumeration
members and their integral counterparts without an explicit cast.
As for your difficulty in Googling the subject, try leaving off the word
"pattern" (i.e. "typesafe enum"). Of course, all references you find will be
related to the Java programming language because, as I said, C# enumerations
*are* type-safe.
Hi Steven,
Actually, the Java type-safe enum is similar to .Net enums. It is the older
Java implementation that is exposed only as a class, and is not type-safe.
But it is entirely possible to create a class like that in .Net.
--
HTH,
Kevin Spencer
Microsoft MVP
Software Composer http://unclechutney.blogspot.com
A watched clock never boils.
"Steven Nagy" <le*********@hotmail.comwrote in message
news:11**********************@c28g2000cwb.googlegr oups.com...
Thanks Kevin.
Yes I know enums are type-safe. I was more interested in the actual
pattern.
Its not the aspect of being type-safe that my question relates to, and
I suppose in that context my question could have been misleading.
The pattern is based around providing a class instead of an enum and
thus realising more potential as a class than an enum could. My
interest is around that, and what people have found to be useful about
the pattern, or perhaps what people have discovered that a standard
enum provides that an implementation of the pattern could not.
Thanks,
Steven
Kevin Spencer wrote:
>C# enumerations *are* type-safe. There is no such thing as a non-type-safe enumeration. In C#, enumerations are inherited from the value type System.Enum, which is a structure. There can be no confusion of enumeration members and their integral counterparts without an explicit cast.
As for your difficulty in Googling the subject, try leaving off the word "pattern" (i.e. "typesafe enum"). Of course, all references you find will be related to the Java programming language because, as I said, C# enumerations *are* type-safe.
Hi again Kevin,
Actually, the Java type-safe enum is similar to .Net enums. It is the older
Java implementation that is exposed only as a class, and is not type-safe.
But it is entirely possible to create a class like that in .Net.
Yes and this brings me to the "requested input" from professionals like
yourself.
Do you value the pattern in a C# setting? When do you find yourself
implementing this pattern? What advantages do you see the standard
enums having over an implementation of this pattern in C#?
I'm not interested in syntax, I'm interested in pros and cons.
Cheers,
Steven
Also, could you expand on this a bit more...
and is not type-safe.
Is the type-safe enum pattern not type-safe?
Why is this so? The implementations in Java that I have seen seem to be
type safe.
I guess if I am creating a class called Foo and have this code:
Foo SomeFoo = Foo.Bar;
if (SomeFoo == Foo.Bar) { ... }
Is this not typesafe?
Cheers,
Steven
Here's a simplified explanation: http://java.sun.com/j2se/1.5.0/docs/...age/enums.html
As for whether I think it's a good idea to use the non-type-safe pattern, no
I don't think so, for the reasons explained in the Sun Java reference above.
The .Net enum is the best of all worlds, type-safe, and concise. Very
similar to the original C enum syntax.
--
HTH,
Kevin Spencer
Microsoft MVP
Software Composer http://unclechutney.blogspot.com
A watched clock never boils.
"Steven Nagy" <le*********@hotmail.comwrote in message
news:11**********************@i42g2000cwa.googlegr oups.com...
Also, could you expand on this a bit more...
>and is not type-safe.
Is the type-safe enum pattern not type-safe?
Why is this so? The implementations in Java that I have seen seem to be
type safe.
I guess if I am creating a class called Foo and have this code:
Foo SomeFoo = Foo.Bar;
if (SomeFoo == Foo.Bar) { ... }
Is this not typesafe?
Cheers,
Steven
Hi Kevin,
I think we are talking about 2 different things. That link refers to
the "int enum pattern" which is definately not type-safe. However I am
referring to the "type-safe enum pattern" which to my understanding IS
type save and is covered only briefly in that article, saying that its
fault is that it can't be used in a switch statement (in the Java
language). So I guess this brings me to the following lines of thought:
1. I need to check out tonight if coding the equivalence operator in C#
is enough for switch statements. (ie. public static bool operator
==(object a, object b) { ... } )
If this works, or there is at least a specific operator for switch
statements, then the only identified fault with the typesafe enum
pattern in java does not apply to .NET.
2. From what I can tell, Java allows you to write static methods inline
with your enum, creating that encapsulation. I am not sure if C# lets
you do this as well. Something else to investigate when I get home
tonight.
As for whether I think it's a good idea to use the non-type-safe pattern, no
I was referring to the type safe pattern, not the non-type-safe
pattern.
I don't think so, for the reasons explained in the Sun Java reference above.
The .Net enum is the best of all worlds, type-safe, and concise. Very
Concise is good at times. And sure, for small stuff, the standard enum
is fine. But there comes a time when you need to push the boundaries a
bit, thus back to my original question about pros and cons of both.
Hopefully this has cleared up my position and what I am trying to learn
here.
Cheers,
Steven
Hi Steven,
Here's my take on why I think one should use an Enum instead of a class with a list of constant values:
1. Enum instances act like the underlying Type, which must be a struct, not a class. You won't be able to provide even some of the
same functionality in a class without using operator overloads and even then you won't get editor or compiler support for the
underlying Type. Every time you pass an instance of your class it will be an object reference. Enum values are structs and
therefore instances of an Enum are always passed as a value unless the ref or out parameter modifier is used. (This is true even
though the Enum Type derives from object. You can test this by using the static Object.ReferenceEquals method.)
2. Enums support implicit conversion from and explicit conversion to the underlying Type. (This can be accomplished in a class by
overloading the implicit and explicit casting operators, however)
3. Enums have built-in support for conversion to and from string representations of the underlying Type or the name of the
constants.
4. Enums have built-in support for the FlagsAttribute attribute.
5. Designers have built-in support to handle Enums in a way that is useful to developers.
6. Enums encapsulate a single idea: a list of related constant values with only one "chosen" value at any time. By passing an
instance of an Enum to a method your are essentially passing in one of the constants that it contains. If you need a single value
to be chosen from a list of constants and passed into a related method, for example, I think it's perfectly reasonable to code a
class for the method and an Enum for the constants. If you can think of an example where it would be reasonable to combine a class
and an Enum into a single Type I'd love to here it because I couldn't think of one.
HTH
--
Dave Sexton
"Steven Nagy" <le*********@hotmail.comwrote in message news:11**********************@c28g2000cwb.googlegr oups.com...
Thanks Kevin.
Yes I know enums are type-safe. I was more interested in the actual
pattern.
Its not the aspect of being type-safe that my question relates to, and
I suppose in that context my question could have been misleading.
The pattern is based around providing a class instead of an enum and
thus realising more potential as a class than an enum could. My
interest is around that, and what people have found to be useful about
the pattern, or perhaps what people have discovered that a standard
enum provides that an implementation of the pattern could not.
Thanks,
Steven
Kevin Spencer wrote:
>C# enumerations *are* type-safe. There is no such thing as a non-type-safe enumeration. In C#, enumerations are inherited from the value type System.Enum, which is a structure. There can be no confusion of enumeration members and their integral counterparts without an explicit cast.
As for your difficulty in Googling the subject, try leaving off the word "pattern" (i.e. "typesafe enum"). Of course, all references you find will be related to the Java programming language because, as I said, C# enumerations *are* type-safe.
Kevin Spencer <uc*@ftc.govwrote:
Here's a simplified explanation: http://java.sun.com/j2se/1.5.0/docs/...age/enums.html
As for whether I think it's a good idea to use the non-type-safe pattern, no
I don't think so, for the reasons explained in the Sun Java reference above.
The .Net enum is the best of all worlds, type-safe, and concise. Very
similar to the original C enum syntax.
The .NET enum is a very long way from the best of all worlds.
1) It's completely non-OO. Just because there's a fixed set of values,
why should that mean the type can't have any other data (attributes
aren't really adequate or elegate) or behaviour
2) It's not type-safe when it's boxed
3) It allows (and can't disallow) values which aren't in the defined
set
The Java enum is fantastically useful, and I'd love to see an
equivalent - or even better - mechanism in C# and .NET. See http://msmvps.com/blogs/jon.skeet/ar...classenum.aspx
for more on my thoughts about it.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Dave Sexton <dave@jwa[remove.this]online.comwrote:
Here's my take on why I think one should use an Enum instead of a
class with a list of constant values:
1. Enum instances act like the underlying Type, which must be a
struct, not a class. You won't be able to provide even some of the
same functionality in a class without using operator overloads and
even then you won't get editor or compiler support for the underlying
Type. Every time you pass an instance of your class it will be an
object reference. Enum values are structs and therefore instances of
an Enum are always passed as a value unless the ref or out parameter
modifier is used. (This is true even though the Enum Type derives
from object. You can test this by using the static
Object.ReferenceEquals method.)
I don't see why passing a reference by value is any worse than passing
an int by value.
2. Enums support implicit conversion from and explicit conversion to
the underlying Type. (This can be accomplished in a class by
overloading the implicit and explicit casting operators, however)
Only explicit conversion, aside from the constant of 0. Why is this an
advantage though? If you want to attach an integral value to the class-
based enum, you can easily do so.
3. Enums have built-in support for conversion to and from string
representations of the underlying Type or the name of the constants.
Easy to achieve manually, and could be easily automatic with more
compiler and CLR support. (It's available in Java 5 enums.)
4. Enums have built-in support for the FlagsAttribute attribute.
Java has EnumSet, which you easily build an equivalent of.
5. Designers have built-in support to handle Enums in a way that is
useful to developers.
Again, that's only because .NET doesn't have enhanced enums yet.
6. Enums encapsulate a single idea: a list of related constant values
with only one "chosen" value at any time. By passing an instance of
an Enum to a method your are essentially passing in one of the
constants that it contains. If you need a single value to be chosen
from a list of constants and passed into a related method, for
example, I think it's perfectly reasonable to code a class for the
method and an Enum for the constants. If you can think of an example
where it would be reasonable to combine a class and an Enum into a
single Type I'd love to here it because I couldn't think of one.
Enums provide a link between a name and a value within a namespace (the
enum type). That's all - and that sucks. Do you insist that all your
other types only have one or two pieces of data and very limited
behaviour? Why should the related values not have extra data?
I suspect you can't see the uses for more advanced functionality
because you haven't *had* that advanced functionality. I've found that
it takes Java programmers quite a while to embrace enhanced enums, but
that when they do there are several "natural fits" which make the
coding *much* nicer.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Hi Jon,
>1. Enum instances act like the underlying Type, which must be a struct, not a class. You won't be able to provide even some of the same functionality in a class without using operator overloads and even then you won't get editor or compiler support for the underlying Type. Every time you pass an instance of your class it will be an object reference. Enum values are structs and therefore instances of an Enum are always passed as a value unless the ref or out parameter modifier is used. (This is true even though the Enum Type derives from object. You can test this by using the static Object.ReferenceEquals method.)
I don't see why passing a reference by value is any worse than passing
an int by value.
I'm not sure what you mean by that. I was just trying to explain that an instance of an Enum acutally behaves like a value-type
(Curiously though, VS.NET shows "class" on the tooltip for "Enum" in code, although it derives from ValueType). If you want to
produce the same functionality as Enums (or as close as you can get, but with custom state and behavior) using the tools that are
currently at your disposal, then you'd be better off using a struct, not a class.
I think this directly addresses the point of the OP. The author claims to have written a class using the current framework, at
least so it seems, to extend the Enum type. I intended my reply to address some of the concerns I would have if someone gave me
this new class and I had to use it in place of Enums.
>2. Enums support implicit conversion from and explicit conversion to the underlying Type. (This can be accomplished in a class by overloading the implicit and explicit casting operators, however)
Only explicit conversion, aside from the constant of 0. Why is this an
advantage though? If you want to attach an integral value to the class-
based enum, you can easily do so.
My mistake on the implicit part.
It's an advantage because Enum already exists as a primitive in the framework, supplying that functionality. The point is that you
can code it in a class by using casting overloads however it's just more work trying to reinvent the wheel, IMO.
>3. Enums have built-in support for conversion to and from string representations of the underlying Type or the name of the constants.
Easy to achieve manually, and could be easily automatic with more
compiler and CLR support. (It's available in Java 5 enums.)
Of course it's easy, but it's just more work trying to reinvent the wheel before you can extend its behavior.
I was listing all of the aspects of Enum that one would have to reproduce if they wanted to extend its behavior using a class in the
current framework. The point being that Enum is a primitive Type that already provides all of this functionality. My last point
addresses why I think this is important.
Maybe I can make my POV clearer by asking you if you have a class that you wrote in .NET that extends enums and that you use in
place of them? If not, that's my point exactly. If so, then I give up. I'm easy ;)
>4. Enums have built-in support for the FlagsAttribute attribute.
Java has EnumSet, which you easily build an equivalent of.
I'm not arguing that a more robust Enum type, as a primitive, wouldn't be a welcomed addition. Again I'm just trying to address the
OP. Enums have that support now and I would expect the author's class to have it as well before I used it in place of Enums.
>5. Designers have built-in support to handle Enums in a way that is useful to developers.
Again, that's only because .NET doesn't have enhanced enums yet.
Yet. But I don't think that addresses the OP ;) The author wrote a custom class using the current framework. If the author
wishes to extend their class for designer support they could do so, of course, but personally I'd rather just use a simple Enum
right now.
>6. Enums encapsulate a single idea: a list of related constant values with only one "chosen" value at any time. By passing an instance of an Enum to a method your are essentially passing in one of the constants that it contains. If you need a single value to be chosen from a list of constants and passed into a related method, for example, I think it's perfectly reasonable to code a class for the method and an Enum for the constants. If you can think of an example where it would be reasonable to combine a class and an Enum into a single Type I'd love to here it because I couldn't think of one.
Enums provide a link between a name and a value within a namespace (the
enum type). That's all - and that sucks. Do you insist that all your
other types only have one or two pieces of data and very limited
behaviour? Why should the related values not have extra data?
Ok, I don't insist that all of my other types have only one or two pieces of data and very limited behavior, however I do insist
that they aren't framework primitives that address a particular, compile-time need ;)
I suspect you can't see the uses for more advanced functionality
because you haven't *had* that advanced functionality. I've found that
it takes Java programmers quite a while to embrace enhanced enums, but
that when they do there are several "natural fits" which make the
coding *much* nicer.
Well, I never said that! My post wasn't against the idea of a primitive Type that addresses your concerns, but instead it was
against the idea of creating an Enum-enhanced type using a class in the current framework. After reading your article I can see how
I might benefit from it, however I do agree that if I had it and used it, I could probably appreciate the idea more than I do now.
As for the lack of Type-safety in Enums I don't think it's any reason to be concerned. They are value-types, so it's the value that
is important, not the Type.
--
Dave Sexton
I'm not sure what you mean by that. I was just trying to explain that an instance of an Enum acutally behaves like a value-type
(Curiously though, VS.NET shows "class" on the tooltip for "Enum" in code, although it derives from ValueType). If you want to
produce the same functionality as Enums (or as close as you can get, but with custom state and behavior) using the tools that are
currently at your disposal, then you'd be better off using a struct, not a class.
I think this directly addresses the point of the OP. The author claims to have written a class using the current framework, at
least so it seems, to extend the Enum type. I intended my reply to address some of the concerns I would have if someone gave me
this new class and I had to use it in place of Enums.
Well its no claim, its fact... but I'm just adhering to the concepts of
the pattern. Its very well documented.
Here's a brief sample from my chess application (note that there's
nothing really in here that you can't do currently with enums and
attributes):
public class GameStatus
{
private int _value = 0;
public int Value
{
get
{
return _value;
}
}
private string _title = "";
public string Title
{
get
{
return _title;
}
}
public static readonly GameStatus WhiteWins = new GameStatus(3,
"White Wins");
public static readonly GameStatus BlackWins = new GameStatus(4,
"Black Wins");
public static readonly GameStatus Stalemate = new GameStatus(5,
"Stalemate");
private GameStatus(int value, string title)
{
_value = value;
_title = title;
}
public override string ToString()
{
return _title.Replace(" ", "");
}
public static bool operator ==(GameStatus gs1, GameStatus gs2)
{
return (gs1.Value == gs2.Value);
}
public static bool operator !=(GameStatus gs1, GameStatus gs2)
{
return (gs1.Value != gs2.Value);
}
}
I'm not arguing that a more robust Enum type, as a primitive, wouldn't be a welcomed addition. Again I'm just trying to address the
OP. Enums have that support now and I would expect the author's class to have it as well before I used it in place of Enums.
Its not a general replacement for enums.. its a specific scenario as
per the example above.
Its not like I am writing " public class ABetterEnum : Enum { ... } "
Again, that's only because .NET doesn't have enhanced enums yet.
Yet. But I don't think that addresses the OP ;) The author wrote a custom class using the current framework. If the author
wishes to extend their class for designer support they could do so, of course, but personally I'd rather just use a simple Enum
right now.
I think this is off topic. I think at this point we all concede that we
can replicate an enum with a class.
6. Enums encapsulate a single idea: a list of related constant values
What if that single idea is bigger than what the enum can support?
Enums provide a link between a name and a value within a namespace (the
enum type). That's all - and that sucks. Do you insist that all your
other types only have one or two pieces of data and very limited
behaviour? Why should the related values not have extra data?
I think this is one of the key pros for the pattern that I was looking
for. With enums, its the value (usually numeric) and the actual enum
constant name. With a class implementation its 2 to infinity (and
beyond!). So in my code example above, I actually have 3: the int
value, the string title (which in this case is a friendly name that can
show in screen) and a usable name (shown in the ToString() method).
Ok, I don't insist that all of my other types have only one or two pieces of data and very limited behavior, however I do insist
that they aren't framework primitives that address a particular, compile-time need ;)
Oh but they do address a compile-time need.
I can write code like this:
GameStatus CurrentStatus = GameStatus.WhiteWins;
Label1.Text = CurrentStatus.Title;
I suspect you can't see the uses for more advanced functionality
because you haven't *had* that advanced functionality. I've found that
it takes Java programmers quite a while to embrace enhanced enums, but
that when they do there are several "natural fits" which make the
coding *much* nicer.
I admit that I had heard of the pattern only recently and it is
incredibly rare in .NET circles (as far as I can tell) but not useless.
As for the lack of Type-safety in Enums I don't think it's any reason to be concerned. They are value-types, so it's the value that
is important, not the Type.
I'm sorry but I disagree. The Type is extremely important. I'd rather
see errors at compile time than at run-time.
I really appreciate both your inputs in this, so please, both keep
posting!
Steven
On a similar vain, you could also do something here by marking the
individual enum values with attributes to hold the full name, and a helper
class to obtain these as required (see below); only nuicance here is that
the helper class must use reflection (.GetCustomAttributes) on the enum
values (held as fields on the Type). And globalization would still need some
kind of lookup code in the But in its favor:
* The same helper class can be used with any enum
* It is faithful to the CLR enum model
* Like the OP, supports (in theory) multiple characteristics by extending
the attribute or adding additional attributes
I'm not saying it's the worlds best implementation ever... but it works ;-p
Marc
(add [EnumMarkup("Some Description")] before an enum item definition)
[AttributeUsage(AttributeTargets.Field, AllowMultiple=false)]
public class EnumMarkupAttribute : Attribute {
public readonly string Description;
public EnumMarkupAttribute(string description) {
if (description == null) throw new
ArgumentNullException("description");
Description = description;
}
}
public static class EnumHelper<Twhere T : struct {
private static Dictionary<T, string_valueToDescription;
private static Dictionary<string, T _descriptionToValue;
static EnumHelper() {
Type enumType = typeof(T), attributeType =
typeof(EnumMarkupAttribute);
_descriptionToValue = new Dictionary<string, T>();
_valueToDescription = new Dictionary<T, string>();
foreach (string name in Enum.GetNames(enumType)) {
T value = (T) Enum.Parse(enumType, name);
string desc = name;
foreach (EnumMarkupAttribute attrib in
enumType.GetField(value.ToString()).GetCustomAttri butes(attributeType,
false)) {
desc = attrib.Description;
break; // only expect one per enum value anyway!
}
_valueToDescription[value] = desc;
_descriptionToValue[desc] = value;
}
}
public static T ParseDescription(string description) {
T value;
if (!_descriptionToValue.TryGetValue(description, out value)) {
throw new ArgumentException(string.Format("Enum \"{0}\" not
found by description \"{1}\"",typeof(T).Name, description ?? "<null>"),
"description");
}
return value;
}
public static string GetDescription(T value) {
string description;
if (!_valueToDescription.TryGetValue(value, out description)) {
description = value.ToString();
}
return description;
}
public static string GetName(T value) {
return Enum.GetName(typeof(T), value);
}
public static T ParseName(string value) {
return (T)Enum.Parse(typeof(T), value);
}
public static T ParseName(string value, bool ignoreCase) {
return (T)Enum.Parse(typeof(T), value, ignoreCase);
}
public static T[] GetValues() {
Array array = Enum.GetValues(typeof(T));
T[] result = new T[array.Length];
array.CopyTo(result, 0);
return result;
}
public static string[] GetNames() {
return Enum.GetNames(typeof(T));
}
public static string[] GetDescriptions() {
T[] values = GetValues();
int length = values.Length;
string[] result = new string[length];
for (int i = 0; i < length; i++) {
result[i] = GetDescription(values[i]);
}
return result;
}
}
Hi Steven,
>I'm not sure what you mean by that. I was just trying to explain that an instance of an Enum acutally behaves like a value-type (Curiously though, VS.NET shows "class" on the tooltip for "Enum" in code, although it derives from ValueType). If you want to produce the same functionality as Enums (or as close as you can get, but with custom state and behavior) using the tools that are currently at your disposal, then you'd be better off using a struct, not a class.
I think this directly addresses the point of the OP. The author claims to have written a class using the current framework, at least so it seems, to extend the Enum type. I intended my reply to address some of the concerns I would have if someone gave me this new class and I had to use it in place of Enums.
Well its no claim, its fact... but I'm just adhering to the concepts of
the pattern. Its very well documented.
At least I can be sure of that. Thanks for posting the code snippet too.
Here's a brief sample from my chess application (note that there's
nothing really in here that you can't do currently with enums and
attributes):
<snip>
Your class should probably be a struct, and in that case you should override Equals and GetHashCode as well. Also, you might want
to implement IComparable<GameStatusand IEquatable<GameStatus>. Other than that, it looks good to me.
>I'm not arguing that a more robust Enum type, as a primitive, wouldn't be a welcomed addition. Again I'm just trying to address the OP. Enums have that support now and I would expect the author's class to have it as well before I used it in place of Enums.
Its not a general replacement for enums.. its a specific scenario as
per the example above.
Its not like I am writing " public class ABetterEnum : Enum { ... } "
Well, you did write code so that your class would exhibit the behavior of Enum before you could "extend" it, otherwise it wouldn't
have replaced Enum. Essentially, you have combined a class with an enum. In the current framework, that's really your only choice
to meet your specific needs.
Again, that's only because .NET doesn't have enhanced enums yet.
Yet. But I don't think that addresses the OP ;) The author wrote a custom class using the current framework. If the author wishes to extend their class for designer support they could do so, of course, but personally I'd rather just use a simple Enum right now.
I think this is off topic. I think at this point we all concede that we
can replicate an enum with a class.
If you have the time and desire, yes ;)
>6. Enums encapsulate a single idea: a list of related constant values
What if that single idea is bigger than what the enum can support?
Then you should use a different architecture. I never said that you have to use enums.
Enums provide a link between a name and a value within a namespace (the
enum type). That's all - and that sucks. Do you insist that all your
other types only have one or two pieces of data and very limited
behaviour? Why should the related values not have extra data?
I think this is one of the key pros for the pattern that I was looking
for. With enums, its the value (usually numeric) and the actual enum
constant name. With a class implementation its 2 to infinity (and
beyond!). So in my code example above, I actually have 3: the int
value, the string title (which in this case is a friendly name that can
show in screen) and a usable name (shown in the ToString() method).
Well then you can't use an Enum if you need more functionality then it provides. It's just that simple. In the current framework,
if you implement it as a class then you really can't call it an Enum. It's a custom Type.
You asked in your OP to provide an argument for the use of Enums. I think I did just that. They provide some specific needs and
they do it well. Now, it seems, that you wanted arguments against the proposition of extensions to enums in a later framework
version, but I'm not against that. ;)
>Ok, I don't insist that all of my other types have only one or two pieces of data and very limited behavior, however I do insist that they aren't framework primitives that address a particular, compile-time need ;)
Oh but they do address a compile-time need.
I can write code like this:
GameStatus CurrentStatus = GameStatus.WhiteWins;
Label1.Text = CurrentStatus.Title;
I think Jon was suggesting that Enum, as a primitive, is too restrictive but he tried to illustrate that point by suggesting that it
wouldn't make sense if my classes had to sacrifice data too. I'm not suggesting that your implementation doesn't address some
specific compile-time need, I'm simply suggesting that Enums do and that custom Types that don't provide the same functionality as
Enums can't be compared to them. If I need more than an Enum offers, I can always create a class, for now :)
<snip>
>As for the lack of Type-safety in Enums I don't think it's any reason to be concerned. They are value-types, so it's the value that is important, not the Type.
I'm sorry but I disagree. The Type is extremely important. I'd rather
see errors at compile time than at run-time.
Well, that's impossible if you are using FlagsAttribute and relying on external input that isn't type safe. Here it's the value
that is important, not the Type. I believe that is the case with most, if not all, value-types. Semantically, I think that's the
point.
I do, of course, appreciate Type safety but it's just not always possible, or reasonable for that matter.
I really appreciate both your inputs in this, so please, both keep
posting!
NP.
--
Dave Sexton
Hi Jon,
I do appreciate the language enhancements that continue to evolve in C#, but
to me an enum is an enum (as in the original C spec), and a class is a
class. I would have no problem with MS adding such a class, but I have no
desire to see it done either. If I need one, I can always write one.
--
HTH,
Kevin Spencer
Microsoft MVP
Software Composer http://unclechutney.blogspot.com
A watched clock never boils.
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP************************@msnews.microsoft.c om...
Kevin Spencer <uc*@ftc.govwrote:
>Here's a simplified explanation: http://java.sun.com/j2se/1.5.0/docs/...age/enums.html
As for whether I think it's a good idea to use the non-type-safe pattern, no I don't think so, for the reasons explained in the Sun Java reference above. The .Net enum is the best of all worlds, type-safe, and concise. Very similar to the original C enum syntax.
The .NET enum is a very long way from the best of all worlds.
1) It's completely non-OO. Just because there's a fixed set of values,
why should that mean the type can't have any other data (attributes
aren't really adequate or elegate) or behaviour
2) It's not type-safe when it's boxed
3) It allows (and can't disallow) values which aren't in the defined
set
The Java enum is fantastically useful, and I'd love to see an
equivalent - or even better - mechanism in C# and .NET. See http://msmvps.com/blogs/jon.skeet/ar...classenum.aspx
for more on my thoughts about it.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Marc Gravell <ma**********@gmail.comwrote:
On a similar vain, you could also do something here by marking the
individual enum values with attributes to hold the full name, and a helper
class to obtain these as required (see below); only nuicance here is that
the helper class must use reflection (.GetCustomAttributes) on the enum
values (held as fields on the Type). And globalization would still need some
kind of lookup code in the But in its favor:
* The same helper class can be used with any enum
* It is faithful to the CLR enum model
* Like the OP, supports (in theory) multiple characteristics by extending
the attribute or adding additional attributes
Downsides:
1) It only works with values which are available as attributes (okay in
this particular case, but not in general)
2) It's ugly
3) It leaves the same issue of invalid enum values (i.e. any integral
value of the appropriate type can be cast to the enum type)
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Kevin Spencer <uc*@ftc.govwrote:
I do appreciate the language enhancements that continue to evolve in C#, but
to me an enum is an enum (as in the original C spec), and a class is a
class. I would have no problem with MS adding such a class, but I have no
desire to see it done either. If I need one, I can always write one.
An "enum" is just an enumeration of values as far as I'm concerned. You
can't apply attributes to C enums - so does that mean we shouldn't be
able to apply them in C#? Why is enum different to struct? There are
lots of things you can do with C# structs which you can't do with C
structs - they've become object-oriented. Why not perform the same sort
of change to enums?
And while you *can* write one, there are disadvantages to doing so
compared with having a version in the language/framework:
1) Different people will have different implementations
2) You can't use it (elegantly) in a switch statement
3) There's extra code to be written which could easily be provided by
the framework
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Well, yes, this is object-oriented, but for some reason I just can't see
redefining a type so radically. It seems like redefining integer, or byte as
an object. IMHO, it would be better to add a new type.
--
Kevin Spencer
Microsoft MVP
Software Composer http://unclechutney.blogspot.com
A watched clock never boils.
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP************************@msnews.microsoft.c om...
Kevin Spencer <uc*@ftc.govwrote:
>I do appreciate the language enhancements that continue to evolve in C#, but to me an enum is an enum (as in the original C spec), and a class is a class. I would have no problem with MS adding such a class, but I have no desire to see it done either. If I need one, I can always write one.
An "enum" is just an enumeration of values as far as I'm concerned. You
can't apply attributes to C enums - so does that mean we shouldn't be
able to apply them in C#? Why is enum different to struct? There are
lots of things you can do with C# structs which you can't do with C
structs - they've become object-oriented. Why not perform the same sort
of change to enums?
And while you *can* write one, there are disadvantages to doing so
compared with having a version in the language/framework:
1) Different people will have different implementations
2) You can't use it (elegantly) in a switch statement
3) There's extra code to be written which could easily be provided by
the framework
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Kevin Spencer <uc*@ftc.govwrote:
Well, yes, this is object-oriented, but for some reason I just can't see
redefining a type so radically. It seems like redefining integer, or byte as
an object. IMHO, it would be better to add a new type.
Why though? When we've already got the concept of an enum, which is
just very limited, why not embrace the idea of making it properly OO?
I can understand the reluctance to some extent, because even after I
knew about Java enums, I hadn't realised quite how useful they'd be
until I started living with them for a while. It's one of those ideas
which takes a while to sink in. It's also one of those things I miss
intensely when I come back from Java to C#...
Still, now that Mads is on the C# team, maybe we'll see them in a
future release :)
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Dave Sexton <dave@jwa[remove.this]online.comwrote:
1. Enum instances act like the underlying Type, which must be a
struct, not a class. You won't be able to provide even some of the
same functionality in a class without using operator overloads and
even then you won't get editor or compiler support for the underlying
Type. Every time you pass an instance of your class it will be an
object reference. Enum values are structs and therefore instances of
an Enum are always passed as a value unless the ref or out parameter
modifier is used. (This is true even though the Enum Type derives
from object. You can test this by using the static
Object.ReferenceEquals method.)
I don't see why passing a reference by value is any worse than passing
an int by value.
I'm not sure what you mean by that. I was just trying to explain that
an instance of an Enum acutally behaves like a value-type (Curiously
though, VS.NET shows "class" on the tooltip for "Enum" in code,
although it derives from ValueType).
Both Enum and ValueType are classes, in fact.
If you want to produce the same
functionality as Enums (or as close as you can get, but with custom
state and behavior) using the tools that are currently at your
disposal, then you'd be better off using a struct, not a class.
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.
I think this directly addresses the point of the OP. The author
claims to have written a class using the current framework, at least
so it seems, to extend the Enum type. I intended my reply to address
some of the concerns I would have if someone gave me this new class
and I had to use it in place of Enums.
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. 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.
2. Enums support implicit conversion from and explicit conversion to
the underlying Type. (This can be accomplished in a class by
overloading the implicit and explicit casting operators, however)
Only explicit conversion, aside from the constant of 0. Why is this an
advantage though? If you want to attach an integral value to the class-
based enum, you can easily do so.
My mistake on the implicit part.
It's an advantage because Enum already exists as a primitive in the
framework, supplying that functionality. The point is that you can
code it in a class by using casting overloads however it's just more
work trying to reinvent the wheel, IMO.
Well, not really a primitive, but it certainly exists in the framework
as a first-class citizen.
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.
3. Enums have built-in support for conversion to and from string
representations of the underlying Type or the name of the constants.
Easy to achieve manually, and could be easily automatic with more
compiler and CLR support. (It's available in Java 5 enums.)
Of course it's easy, but it's just more work trying to reinvent the
wheel before you can extend its behavior.
I was listing all of the aspects of Enum that one would have to
reproduce if they wanted to extend its behavior using a class in the
current framework. The point being that Enum is a primitive Type that
already provides all of this functionality. My last point addresses
why I think this is important.
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.
Maybe I can make my POV clearer by asking you if you have a class
that you wrote in .NET that extends enums and that you use in place
of them? If not, that's my point exactly. If so, then I give up. I'm
easy ;)
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.
4. Enums have built-in support for the FlagsAttribute attribute.
Java has EnumSet, which you easily build an equivalent of.
I'm not arguing that a more robust Enum type, as a primitive,
wouldn't be a welcomed addition. Again I'm just trying to address the
OP. Enums have that support now and I would expect the author's class
to have it as well before I used it in place of Enums.
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.
5. Designers have built-in support to handle Enums in a way that is
useful to developers.
Again, that's only because .NET doesn't have enhanced enums yet.
Yet. But I don't think that addresses the OP ;) The author wrote a
custom class using the current framework. If the author wishes to
extend their class for designer support they could do so, of course,
but personally I'd rather just use a simple Enum right now.
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.
6. Enums encapsulate a single idea: a list of related constant values
with only one "chosen" value at any time. By passing an instance of
an Enum to a method your are essentially passing in one of the
constants that it contains. If you need a single value to be chosen
from a list of constants and passed into a related method, for
example, I think it's perfectly reasonable to code a class for the
method and an Enum for the constants. If you can think of an example
where it would be reasonable to combine a class and an Enum into a
single Type I'd love to here it because I couldn't think of one.
Enums provide a link between a name and a value within a namespace (the
enum type). That's all - and that sucks. Do you insist that all your
other types only have one or two pieces of data and very limited
behaviour? Why should the related values not have extra data?
Ok, I don't insist that all of my other types have only one or two
pieces of data and very limited behavior, however I do insist that
they aren't framework primitives that address a particular,
compile-time need ;)
I'm not sure I see your point.
I suspect you can't see the uses for more advanced functionality
because you haven't *had* that advanced functionality. I've found that
it takes Java programmers quite a while to embrace enhanced enums, but
that when they do there are several "natural fits" which make the
coding *much* nicer.
Well, I never said that! My post wasn't against the idea of a
primitive Type that addresses your concerns, but instead it was
against the idea of creating an Enum-enhanced type using a class in
the current framework. After reading your article I can see how I
might benefit from it, however I do agree that if I had it and used
it, I could probably appreciate the idea more than I do now.
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.
As for the lack of Type-safety in Enums I don't think it's any reason
to be concerned. They are value-types, so it's the value that is
important, not the Type.
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.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
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.
So whats the actual current solution here?
Jon, you are obviously very passionate about improvements to the enum
in future releases, but my issues exist now. That's why I found my way
to the type-safe enum pattern to begin with. What do you think of this
pattern, or can you suggest a better way? My previous code snippet was
based on some examples I found in java. I want to make sure I do this
properly the first time, because I might actually be using them in my
DAL.
Also, imagine the very common scenario where you have a table in DB
with static values. Something like what I have specified above in
chess... ways that a game could be ended (WhiteWins, BlackWins, Draw).
Because these values are not going to change for the life of the
solution, I want to have these represented as an enum. Do you think
using the ts enum pattern is a reasonable approach to representing that
mode? I'm sure state pattern would be applicable somewhere as well, but
for now I'm not managing the game's state, just creating passable
values to represent that state. Is this the best approach?
Cheers,
SN
Kevin Spencer wrote:
Actually, the Java type-safe enum is similar to .Net enums. It is the older
Java implementation that is exposed only as a class, and is not type-safe.
The old Java enum pattern (Bloch style) is the same
as what is generated behind the scene for Java 1.5 enum
and it is very type safe.
You can say that it is even more type safe than C# enum's,
because you can not even explicit type cast it to an int.
Arne
Jon Skeet [C# MVP] wrote:
I can understand the reluctance to some extent, because even after I
knew about Java enums, I hadn't realised quite how useful they'd be
until I started living with them for a while. It's one of those ideas
which takes a while to sink in. It's also one of those things I miss
intensely when I come back from Java to C#...
Still, now that Mads is on the C# team, maybe we'll see them in a
future release :)
Two words: backwards compatibility.
Changing enums could break a lot of code.
Arne
Hi Jon,
>1. Enum instances act like the underlying Type, which must be a
>struct, not a class. You won't be able to provide even some of
>the same functionality in a class without using operator
>overloads and even then you won't get editor or compiler support
>for the underlying Type. Every time you pass an instance of your
>class it will be an object reference. Enum values are structs and
>therefore instances of an Enum are always passed as a value
>unless the ref or out parameter modifier is used. (This is true
>even though the Enum Type derives from object. You can test this
>by using the static Object.ReferenceEquals method.)
>
I don't see why passing a reference by value is any worse than
passing an int by value.
I'm not sure what you mean by that. I was just trying to explain
that an instance of an Enum acutally behaves like a value-type
(Curiously though, VS.NET shows "class" on the tooltip for "Enum" in
code, although it derives from ValueType).
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.
If you want to produce the same
functionality as Enums (or as close as you can get, but with custom
state and behavior) using the tools that are currently at your
disposal, then you'd be better off using a struct, not a class.
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 this directly addresses the point of the OP. The author
claims to have written a class using the current framework, at least
so it seems, to extend the Enum type. I intended my reply to address
some of the concerns I would have if someone gave me this new class
and I had to use it in place of Enums.
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.
>2. Enums support implicit conversion from and explicit conversion
>to the underlying Type. (This can be accomplished in a class by
>overloading the implicit and explicit casting operators, however)
>
Only explicit conversion, aside from the constant of 0. Why is
this an advantage though? If you want to attach an integral value
to the class- based enum, you can easily do so.
My mistake on the implicit part.
It's an advantage because Enum already exists as a primitive in the
framework, supplying that functionality. The point is that you can
code it in a class by using casting overloads however it's just more
work trying to reinvent the wheel, 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.
>3. Enums have built-in support for conversion to and from string
>representations of the underlying Type or the name of the constants.
>
Easy to achieve manually, and could be easily automatic with more
compiler and CLR support. (It's available in Java 5 enums.)
Of course it's easy, but it's just more work trying to reinvent the
wheel before you can extend its behavior.
I was listing all of the aspects of Enum that one would have to
reproduce if they wanted to extend its behavior using a class in the
current framework. The point being that Enum is a primitive Type
that already provides all of this functionality. My last point
addresses why I think this is important.
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.
Maybe I can make my POV clearer by asking you if you have a class
that you wrote in .NET that extends enums and that you use in place
of them? If not, that's my point exactly. If so, then I give up. I'm
easy ;)
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.
>4. Enums have built-in support for the FlagsAttribute attribute.
>
Java has EnumSet, which you easily build an equivalent of.
I'm not arguing that a more robust Enum type, as a primitive,
wouldn't be a welcomed addition. Again I'm just trying to address
the OP. Enums have that support now and I would expect the author's
class to have it as well before I used it in place of Enums.
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.
>5. Designers have built-in support to handle Enums in a way that
>is useful to developers.
>
Again, that's only because .NET doesn't have enhanced enums yet.
Yet. But I don't think that addresses the OP ;) The author wrote a
custom class using the current framework. If the author wishes to
extend their class for designer support they could do so, of course,
but personally I'd rather just use a simple Enum right now.
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.
>6. Enums encapsulate a single idea: a list of related constant
>values with only one "chosen" value at any time. By passing an
>instance of an Enum to a method your are essentially passing in
>one of the constants that it contains. If you need a single value
>to be chosen from a list of constants and passed into a related
>method, for example, I think it's perfectly reasonable to code a
>class for the method and an Enum for the constants. If you can
>think of an example where it would be reasonable to combine a
>class and an Enum into a single Type I'd love to here it because I couldn't think of one.
>
Enums provide a link between a name and a value within a namespace
(the enum type). That's all - and that sucks. Do you insist that
all your other types only have one or two pieces of data and very
limited behaviour? Why should the related values not have extra data?
Ok, I don't insist that all of my other types have only one or two
pieces of data and very limited behavior, however I do insist that
they aren't framework primitives that address a particular,
compile-time need ;)
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.
I suspect you can't see the uses for more advanced functionality
because you haven't *had* that advanced functionality. I've found
that it takes Java programmers quite a while to embrace enhanced
enums, but that when they do there are several "natural fits"
which make the coding *much* nicer.
Well, I never said that! My post wasn't against the idea of a
primitive Type that addresses your concerns, but instead it was
against the idea of creating an Enum-enhanced type using a class in
the current framework. After reading your article I can see how I
might benefit from it, however I do agree that if I had it and used
it, I could probably appreciate the idea more than I do now.
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.
As for the lack of Type-safety in Enums I don't think it's any
reason to be concerned. They are value-types, so it's the value that
is important, not the Type.
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.
--
Dave Sexton
Steven Nagy <le*********@hotmail.comwrote:
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.
So whats the actual current solution here?
Jon, you are obviously very passionate about improvements to the enum
in future releases, but my issues exist now. That's why I found my way
to the type-safe enum pattern to begin with. What do you think of this
pattern, or can you suggest a better way? My previous code snippet was
based on some examples I found in java. I want to make sure I do this
properly the first time, because I might actually be using them in my
DAL.
The best implementation I've seen is the one in the comments for my
blog:
public abstract class ArithmeticOperation
{
private ArithmeticOperation()
{
}
public abstract int Eval(int x, int y);
public static readonly ArithmeticOperation Addition = new Add();
private class Add : ArithmeticOperation
{
public override int Eval(int x, int y)
{
return x + y;
}
}
public static readonly ArithmeticOperation Multiplication =
new Multiply();
// ...
}
This uses the fact that nested classes can use private constructors.
The only big downside of this is that you can't use the values in a
switch statement - and that it's a bit ugly, having to declare the
value separately from the class.
Also, imagine the very common scenario where you have a table in DB
with static values. Something like what I have specified above in
chess... ways that a game could be ended (WhiteWins, BlackWins, Draw).
Because these values are not going to change for the life of the
solution, I want to have these represented as an enum. Do you think
using the ts enum pattern is a reasonable approach to representing that
mode? I'm sure state pattern would be applicable somewhere as well, but
for now I'm not managing the game's state, just creating passable
values to represent that state. Is this the best approach?
I would always first consider whether you can do everything you need
with a "simple" enum. If you can't, the pattern above seems pretty
reasonable to me.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Arne Vajhøj <ar**@vajhoej.dkwrote:
Jon Skeet [C# MVP] wrote:
I can understand the reluctance to some extent, because even after I
knew about Java enums, I hadn't realised quite how useful they'd be
until I started living with them for a while. It's one of those ideas
which takes a while to sink in. It's also one of those things I miss
intensely when I come back from Java to C#...
Still, now that Mads is on the C# team, maybe we'll see them in a
future release :)
Two words: backwards compatibility.
Changing enums could break a lot of code.
Oh, they couldn't just change what the "enum" keyword means. That's why
my blog post suggests using "class enum" to declare one :)
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Dave Sexton <dave@jwa[remove.this]online.comwrote:
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.
What real functionality of enum would you be missing? Note that
although I've always described the rich enum using classes, I don't
think there'd be anything to stop you from using a struct instead if
you wanted to.
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.
I'm still not sure where you're going, I'm afraid. The richer
functionality would allow you to semantically do everything the current
enum does. As Arne pointed out, in fact we'd need to keep the existing
enum anyway, but even if we'd originally had rich enums, I don't think
there's anything you could do with the current enums that you wouldn't
be able to do.
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.
Where do you see the difference between passing an immutable reference
type reference and passing an immutable value type value? I mean in
terms of what you can and can't usefully do, rather than strictly in
terms of implementation details.
It's an advantage because Enum already exists as a primitive in the
framework, supplying that functionality. The point is that you can
code it in a class by using casting overloads however it's just more
work trying to reinvent the wheel, 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.
From the docs for Type.IsPrimitiveImpl:
<quote>
The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32,
UInt32, Int64, UInt64, Char, Double, and Single.
</quote>
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.)
That's fine, and how I understood you :)
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.
Well, at this point Enum *can't* be completely replaced - but I don't
see why we couldn't have syntax which would allow current enum
functionality with rich enums, particularly if you allowed "struct
enum" as well as "class enum".
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.
Quite possibly - but I don't think that makes it wrong of foolish for
Steven to use the same pattern, even though he needs some code of his
own.
Maybe I can make my POV clearer by asking you if you have a class
that you wrote in .NET that extends enums and that you use in place
of them? If not, that's my point exactly. If so, then I give up. I'm
easy ;)
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.
Oh C# is a nicer language *in general*, but there are times I prefer
Java - with rich enums leading the way. Likewise C# generics beat Java
generics for most things, but having co/contravariance can be handy
sometimes.
My point was that you really can't (or shouldn't rather) replace Enum.
Can't in the real world, certainly. Shouldn't (in an ideal world where
we were having this discussion before .NET ever came out) depends on
whether the replacement could actually cover everything that enum
currently does.
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.
Right.
Yet. But I don't think that addresses the OP ;) The author wrote a
custom class using the current framework. If the author wishes to
extend their class for designer support they could do so, of course,
but personally I'd rather just use a simple Enum right now.
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.
Yes, I wouldn't suggest removing the existing enums - although some of
them *may* benefit from added behaviour, even now.
Ok, I don't insist that all of my other types have only one or two
pieces of data and very limited behavior, however I do insist that
they aren't framework primitives that address a particular,
compile-time need ;)
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.
My point was that fundamentally, in principle, I don't see why enums
should be as limited as they are currently. Just because C has such
limited enums doesn't mean we should be content with that state of
affairs now.
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.
He's replacing a number of uses for the Enum type, I guess. I suspect
we've been talking largely at cross-purposes...
As for the lack of Type-safety in Enums I don't think it's any
reason to be concerned. They are value-types, so it's the value that
is important, not the Type.
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.
I don't see why not - if they were any other type you wouldn't be able
to do it, including other value types.
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 they want to convert from one enum to another, that would be a
good way of doing it. (Easier with rich enums, admittedly...) Why allow
conversions that shouldn't be available?
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).
They don't ensure that the values are actually within the enumerated
set though. You could do:
FileAccess fa = (FileAccess) 123;
Now, I suspect that 123 isn't a valid value for FileAccess - so I don't
think that should be allowed. Of course, prohibiting it would stop
FlagsAttribute from working, so you'd need something like the Java
EnumSet instead, which could internally use a representation like that
anyway.
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).
So provide a user-defined conversion when you need to. Personally I
prefer to pass the name around than the integral value - it's more
descriptive. Either way, you can do it in situations you need it.
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.
Do you like having to do that everywhere though? Sounds like a bit of a
pain to me.
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.
And that's entirely reasonable. I think I'd misunderstood you.
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.
Attributes can *occasionally* be useful like that, but I agree they're
not a good general purpose mechanism for this.
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Hi Jon,
I have no problems either way. This has undoubtedly been a good discussion
of the issues. :-)
--
HTH,
Kevin Spencer
Microsoft MVP
Software Composer http://unclechutney.blogspot.com
A watched clock never boils.
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP************************@msnews.microsoft.c om...
Kevin Spencer <uc*@ftc.govwrote:
>Well, yes, this is object-oriented, but for some reason I just can't see redefining a type so radically. It seems like redefining integer, or byte as an object. IMHO, it would be better to add a new type.
Why though? When we've already got the concept of an enum, which is
just very limited, why not embrace the idea of making it properly OO?
I can understand the reluctance to some extent, because even after I
knew about Java enums, I hadn't realised quite how useful they'd be
until I started living with them for a while. It's one of those ideas
which takes a while to sink in. It's also one of those things I miss
intensely when I come back from Java to C#...
Still, now that Mads is on the C# team, maybe we'll see them in a
future release :)
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Hi Jon,
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.
What real functionality of enum would you be missing? Note that
although I've always described the rich enum using classes, I don't
think there'd be anything to stop you from using a struct instead if
you wanted to.
The functionality that is missing is obvious if you look at the code posted by Steven. His type is a class, doesn't handle
FlagsAttribute, doesn't implement IComparable or IConvertible, won't return true if you call Type.IsEnum, etc. It definately
couldn't replace Enum as is. Without a base type to handle the "class enum" aspect of things, he'd be plucking out functionality
from Enum that he'd like to include each time in a new class. That's why I shun at calling his or another's shot at this pattern in
the current framework Enum or an extension thereof. To me it's just an entirely different entity that uses an enum-type pattern,
but definately doesn't replace Enum -- and that's ok!
After all, Steven could create his own struct that provides almost the same functionality as Int32 except throws an error when -2 is
assigned and returns a nicely formatted ToString value. It doesn't replace Int32, however.
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.
I'm still not sure where you're going, I'm afraid. The richer
functionality would allow you to semantically do everything the current
enum does. As Arne pointed out, in fact we'd need to keep the existing
enum anyway, but even if we'd originally had rich enums, I don't think
there's anything you could do with the current enums that you wouldn't
be able to do.
Actually, I was agreeing with that idea exactly. I just wanted to make the point that one could make those mistakes if one had to
keep recoding the same functionality for enums over and over again just to conform to a desired pattern that Enum doesn't provide
alone. A base Type as you suggested would help to prevent those unwanted mistakes. For now, it's just a pattern without a type and
that could present problems when coding different implementations between classes trying to address the same issues with Enum.
If this pattern is common enough I would love to see a base Type in a subsequent version of the framework. Unfortunately, as you
correclty suggested, I really don't have experience using the pattern and so I cannot accurately judge it's usefulness as a
framework Type.
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.
Where do you see the difference between passing an immutable reference
type reference and passing an immutable value type value? I mean in
terms of what you can and can't usefully do, rather than strictly in
terms of implementation details.
I don't see a difference in terms of useability. They both provide the same functionality to the system.
I think the concept of a value-type applies to Enum more than a reference type does and so does it apply to the pattern, in general.
Obviously choosing between one or the other is important when implementing a base Type. It will directly affect the Type's
useability in hash tables since in a struct you should always provide your own implementation of GetHashCode, for instance, and more
importantly it will change the way the CLR manages the Type's memory. Both points are extremely important when considering the
Type's use in operations that require a high level of performance and scalability.
You've already stated reasons why using a struct instead of your "class" enum proposal wouldn't necessarily be correct, and I do
agree with that because it really is a "class" enum which does extend the behavior of Enum considerably. However, I don't think
it's completely unreasonable to have a need for the same set of functionality on top of a struct, citing the reasons that I just
mentioned above.
It's an advantage because Enum already exists as a primitive in the
framework, supplying that functionality. The point is that you can
code it in a class by using casting overloads however it's just more
work trying to reinvent the wheel, 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.
From the docs for Type.IsPrimitiveImpl:
<quote>
The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32,
UInt32, Int64, UInt64, Char, Double, and Single.
</quote>
I never actually doubted you ;)
>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.)
That's fine, and how I understood you :)
Great! Hopefully we can start chopping off some of these other large paragraphs too because I can't seem to find my scroll box
anymore :)
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.
Well, at this point Enum *can't* be completely replaced - but I don't
see why we couldn't have syntax which would allow current enum
functionality with rich enums, particularly if you allowed "struct
enum" as well as "class enum".
Sounds good to me.
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.
Quite possibly - but I don't think that makes it wrong of foolish for
Steven to use the same pattern, even though he needs some code of his
own.
I don't think it makes him foolish at all either. If the framework doesn't provide a base Type for him to use then he has to make
due with what he's got. But it still won't replace Enum.
Maybe I can make my POV clearer by asking you if you have a class
that you wrote in .NET that extends enums and that you use in place
of them? If not, that's my point exactly. If so, then I give up. I'm
easy ;)
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.
Oh C# is a nicer language *in general*, but there are times I prefer
Java - with rich enums leading the way. Likewise C# generics beat Java
generics for most things, but having co/contravariance can be handy
sometimes.
I'm sure you already have an article on that... or at least on covariance and contravariance. Care to post the link so we can read
up?
>My point was that you really can't (or shouldn't rather) replace Enum.
Can't in the real world, certainly. Shouldn't (in an ideal world where
we were having this discussion before .NET ever came out) depends on
whether the replacement could actually cover everything that enum
currently does.
I like that fact that enums weren't replaced in .NET with a more robust implementation. It's a simple type meant to due simple
things and it does them well. Encapsulation at its finest, IMO. Your proposed extensions could live happily along side of Enums.
Reasons might exist even to use an Enum inside your "class enum".
<snip>
Yet. But I don't think that addresses the OP ;) The author wrote a
custom class using the current framework. If the author wishes to
extend their class for designer support they could do so, of course,
but personally I'd rather just use a simple Enum right now.
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.
Yes, I wouldn't suggest removing the existing enums - although some of
them *may* benefit from added behaviour, even now.
Some, definately. SocketError enum comes to mind. I'd love a programmatically-accessible description straight from the source that
could be displayed to the end-user. As a matter of fact, I bet a lot of Enums would benefit from descriptive fields for each
constant.
Ok, I don't insist that all of my other types have only one or two
pieces of data and very limited behavior, however I do insist that
they aren't framework primitives that address a particular,
compile-time need ;)
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.
My point was that fundamentally, in principle, I don't see why enums
should be as limited as they are currently. Just because C has such
limited enums doesn't mean we should be content with that state of
affairs now.
(BTW when I wrote "On the contrary" I really meant "In other words". I just wrote the wrong phrase without thinking)
I can agree with that POV. I don't think your example illustrated that at all though.
Was the C enum the basis for limiting the functionality of enums in .NET? Was there never any proposal for additional extensions
such as yours before .NET 1.0 was RTM?
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.
He's replacing a number of uses for the Enum type, I guess. I suspect
we've been talking largely at cross-purposes...
I guess so. I was continuously trying to address the two questions from the OP. It sounded to me like Steven was looking for an
argument for the use of the Enum pattern in the current framework as opposed to just using a custom implementation everywhere. I'm
sure I've side-stepped a bit now, however, but I've tried to stay on-point as much as possible.
The 6th point in my OP was debatable against your opposing point of view. I stated that (and asked for evidence) because I've never
used this pattern. From your article, our early discussions and Steven's code example, it became clear to me that the pattern was
indeed useful. I think the source of much confusion was that I changed gears really early on just for that one point. IIRC I
stated that my POV changed a couple of times, though. Looking back, it seems like you and Steven thought that the whole point of my
OP was #6, when in fact it really wasn't. #6 was to debate the pattern only and it wasn't intended to address the questions in the
OP in any way.
Either way, we're covering some interesting topics, IMO.
As for the lack of Type-safety in Enums I don't think it's any
reason to be concerned. They are value-types, so it's the value that
is important, not the Type.
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.
I don't see why not - if they were any other type you wouldn't be able
to do it, including other value types.
Ok, I'm blaming bad code like that on the developer that wrote it and not the framework that allowed it :)
I agree that it would be nice if the compiler didn't allow it, however. Why does it even allow that conversion in the first place?
I completely understand Int32 to Enum : int, as I've already stated, but I really have no idea why A : Enum to B : Enum is allowed
at all. I can't think of any time in the past that I've ever actually done something like that on purpose. I wonder if that
behavior is just a side-effect of the intrinsic ability to cast from Enum to Enum and the way the CLR handles derived Types.
Perhaps it just treats derived Enums as Enums and nothing more. I don't see any operator overloads in Reflector for the Enum type
or derived Enum types.
>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 they want to convert from one enum to another, that would be a
good way of doing it. (Easier with rich enums, admittedly...) Why allow
conversions that shouldn't be available?
I'll agree with that.
>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).
They don't ensure that the values are actually within the enumerated
set though. You could do:
FileAccess fa = (FileAccess) 123;
Now, I suspect that 123 isn't a valid value for FileAccess - so I don't
think that should be allowed. Of course, prohibiting it would stop
FlagsAttribute from working, so you'd need something like the Java
EnumSet instead, which could internally use a representation like that
anyway.
Right. In order to have FlagsAttribute on Enum that functionality is required. So, why is the base Type in .NET that represents
flags, Enum with an Attribute? Maybe they should have seperated the two into distinct Types:
enum E { A, B }
flags F { F0, F1, F2, F4, F8 } // automatic binary sequencing would have been nice, if I can call it that :)
>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).
So provide a user-defined conversion when you need to. Personally I
prefer to pass the name around than the integral value - it's more
descriptive. Either way, you can do it in situations you need it.
User-defined conversion of what? The framework allows an explicit conversion from the base Type to the Enum's Type. Useful when
you only have the integral value, which does happen from time to time, especially when dealing with data from an external system
that you are normalizing into your own through the use of an Enum (common in Interop, in my experience). If I were to derive a type
from your "class enum" I wouldn't expect that built-in coversion to exist already like it does in Enum. I think Enum is special in
that aspect since it can successfully accomplish the cast through CLR support without the need for custom code. As for the other
allowed conversions, I could argue against them too.
I too prefer to serialize an Enum's string representation, for instance, but it's just not always possible due to constraints of the
data model and possibly performance concerns.
>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.
Do you like having to do that everywhere though? Sounds like a bit of a
pain to me.
Yea, it's not fun ;) But we all have things that we dislike about the framework. That one isn't on the top of my list, however,
especially because it's quite rare that it's required. You really only need to do that check when writing public library code that
uses Enums. (Admittedly, I do it internally as well just to aid in debugging, just like Assert)
<snip>
>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.
Attributes can *occasionally* be useful like that, but I agree they're
not a good general purpose mechanism for this.
Yea, I guess if you have a constant value to associate it with and you're already using reflection or don't mind losing out on the
benefits of an OO approach, and performance isn't a concern, and neither is type-saftey, and you can ensure a certain level of trust
(I guess full trust would be required?) when your program runs.
If you said, "Hardly ever", I might agree!
--
Dave Sexton
Hi Jon and Kevin,
I have no problems either way. This has undoubtedly been a good discussion
of the issues. :-)
Yes it has and has given me a lot to work with.
Thankyou both for your constructive input.
Cheers,
Steven
Dave Sexton <dave@jwa[remove.this]online.comwrote:
What real functionality of enum would you be missing? Note that
although I've always described the rich enum using classes, I don't
think there'd be anything to stop you from using a struct instead if
you wanted to.
The functionality that is missing is obvious if you look at the code
posted by Steven.
I think the problem is with the assumption that the original code
posted is the ultimate pattern. It's a start, and no doubt it handles
what Steven wants it to handle, but I'm sure we could do better if we
had a larger set of goals to start with.
I think we've largely agreed on most of the rest of the things in your
message, hence the snippage. Now, I'm not sure whether or not I've got
the time to do this exercise properly, but if we agree on the feature
set that we'd want from a rich enum, we could work out:
1) A pattern or base class to use without any CLR/framework/compiler
support.
2) What could be done with extra support, and from what. (For instance,
switching elegantly would requite extra compiler support, I suspect.)
Are you interested?
--
Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Hi Jon,
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message news:MP***********************@msnews.microsoft.co m...
Dave Sexton <dave@jwa[remove.this]online.comwrote:
What real functionality of enum would you be missing? Note that
although I've always described the rich enum using classes, I don't
think there'd be anything to stop you from using a struct instead if
you wanted to.
>The functionality that is missing is obvious if you look at the code posted by Steven.
I think the problem is with the assumption that the original code
posted is the ultimate pattern. It's a start, and no doubt it handles
what Steven wants it to handle, but I'm sure we could do better if we
had a larger set of goals to start with.
Agreed. My perspective was in-line with Steven's requirements since he started the thread and it was his code snippet. We seem to
have expanded the thread into finding answers to questions that apply to a more general usage of the pattern, but it has proven to
be useful in identifying more requirements to be addressed by your proposed "class enum" type, which seems to address Steven's needs
too.
I think we've largely agreed on most of the rest of the things in your
message, hence the snippage. Now, I'm not sure whether or not I've got
the time to do this exercise properly, but if we agree on the feature
set that we'd want from a rich enum, we could work out:
1) A pattern or base class to use without any CLR/framework/compiler
support.
(I assume you want to target 2.0)
2) What could be done with extra support, and from what. (For instance,
switching elegantly would requite extra compiler support, I suspect.)
Are you interested?
I'm interested in the result, and I'd be more than happy to help out in the design in any way I could. You definately have a lot
more experience than me on this topic, given your background in Java at least, so I'm not sure how much more I could add. I'd like
to try if you think I can help. I'm great at annoying people by playing devil's advocate - that's for sure. :)
As long as there aren't any stringent time constraints on the project I'd be happy to participate.
I'm not sure how you want to collaborate. Feel free to email me if you'd like, or respond to this post. When I get a chance I'll
take a more thorough look at your article on the subject. If you've started a list of the features you'd like to include just link
me to it. If you'd like me to start one or add to yours let me know.
Also, do you know of any other articles to which you could post a link that describes the pattern from a different perspective or in
more detail? (I hope everyone feels free to reply to this question)
(Curiously, no mention of the pattern exists on http://patternshare.org, nor does it exist on Microsoft's Patterns and Practices for
..NET Version 1.1.0 ( http://msdn.microsoft.com/library/de...sp?frame=true).)
--
Another concern I have about the pattern is its relationship to the state machine pattern. The state pattern seems to address the
needs of a developer that would use the class-enum pattern in a more robust way by expanding the pattern out into multiple types.
It will also scale better, it seems. I guess in order for the class-enum pattern to be useful it really shouldn't overlap with
either the Enum or State pattern, but find a place somewhere in between. Some overlap with both Enum and the state pattern is to be
expected.
Here are a few points off the top of my head that I think should be addressed when desiging the pattern's base class (some of which
may turn out to not have any real bearing, but they just seem important enough to mention):
1. Language agnostic (may be consumed by any CLS-compliant language)
2. Performance related to Enum and state pattern. Ideally, I think it should perform better than state pattern in its general use
but not necessarily better than Enum.
3. Scalability in terms of the capability to scale up, increasing the number of constants defined in a derived class, and to scale
out, nesting references to instances of classes derived from the same pattern base (and related ease-of-use compared to the state
pattern when the number needs to grow very high, in which case I think the state pattern might just be a better choice, but that
remains to be seen.)
4. Memory consumption. Find places where the amount of memory consumed by the pattern, in general, can be reduced. Especially in a
base class.
5. Extensibility and flexibility (i.e. Can a derived class override certain methods or otherwise extend the behavior of the class
outside of its intended, general useage scenerios?)
6. GC and related IDisposable issues of the base class and the object instances that a derived class may composite.
Thanks for the discussion. It's been interesting, to say the least.
--
Dave Sexton
The functionality that is missing is obvious if you look at the code
posted by Steven.
I think the problem is with the assumption that the original code
posted is the ultimate pattern. It's a start, and no doubt it handles
what Steven wants it to handle, but I'm sure we could do better if we
had a larger set of goals to start with.
The code I posted was only a small set and designed to illustrate where
I was going with my implementation of the typesafe enum pattern. The
class actually includes a lot more static methods for moving external
decision making steps into the class itself. It is the intention that
if the decision making steps around the enum are incorporated into the
enum object itself, then it becomes easy to scale that enum with
additional values without needing to find every reference in code and
changing it.
The downside is that I find myself halfway to a State implementation,
as mentioned by yourselves. If you guys were to find a happy medium, it
would certainly assist my situation. But finding a way to as
consistantly as possible include the decision making process into the
class-enum itself would be extremely handy. I haven't found a great way
of doing this yet, and am open to suggestions.
1) A pattern or base class to use without any CLR/framework/compiler
support.
I'm a fair bit less knowledgable about pattern construction then you
two.
Does this statement mean that you want the pattern to be platform
independent?
Or that in a .NET context, it doesn't require usage of namespaces such
as Reflection?
Are you interested?
Yes, but I am sure the question was not directed at me.
So I would be just as happy with an outcome.
SN This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Glenn Venzke |
last post by:
I'm writing a class with a method that will accept 1 of 3 items listed in an
enum. Is it possible to pass the item name without the enum name in your
calling statement?
EXAMPLE:
public enum...
|
by: Ozzy Knox |
last post by:
I am trying to convert a string or int variable to an Enum that I have set
up in my C# application. I have tried many options with no success. Any
advice would be appreciated.
Regards
Ozzy
|
by: Jacek Dziedzic |
last post by:
Hi!
I often find that my programs need to store information on
"current mode of something" with two or at most several
mutually exclusive "modes" to choose from, e.g.
- datafile: is it in a)...
|
by: toton |
last post by:
Hi,
I have some enum (enumeration ) defined in some namespace, not inside
class. How to use the enum constant's in some other namespace without
using the whole namespace.
To say in little...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM)
The start time is equivalent to 19:00 (7PM) in Central...
|
by: erikbower65 |
last post by:
Using CodiumAI's pr-agent is simple and powerful. Follow these steps:
1. Install CodiumAI CLI: Ensure Node.js is installed, then run 'npm install -g codiumai' in the terminal.
2. Connect to...
|
by: linyimin |
last post by:
Spring Startup Analyzer generates an interactive Spring application startup report that lets you understand what contributes to the application startup time and helps to optimize it. Support for...
|
by: erikbower65 |
last post by:
Here's a concise step-by-step guide for manually installing IntelliJ IDEA:
1. Download: Visit the official JetBrains website and download the IntelliJ IDEA Community or Ultimate edition based on...
|
by: kcodez |
last post by:
As a H5 game development enthusiast, I recently wrote a very interesting little game - Toy Claw ((http://claw.kjeek.com/))。Here I will summarize and share the development experience here, and hope it...
|
by: DJRhino1175 |
last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this -
If...
|
by: Rina0 |
last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
|
by: DJRhino |
last post by:
Private Sub CboDrawingID_BeforeUpdate(Cancel As Integer)
If = 310029923 Or 310030138 Or 310030152 Or 310030346 Or 310030348 Or _
310030356 Or 310030359 Or 310030362 Or...
|
by: lllomh |
last post by:
Define the method first
this.state = {
buttonBackgroundColor: 'green',
isBlinking: false, // A new status is added to identify whether the button is blinking or not
}
autoStart=()=>{
| |