C# Enums - Feature or deficiency

R

RobertK

Ian Semmel said:
...
Perhaps the C# people should have looked at pascal as well as C++.
Anders Hejlsberg, who headed Microsoft's C# team, had created the Pascal
version that became Turbo Pascal and later worked for Borland on further
developing Turbo Pascal and creating Delphi.
 
N

not_a_commie

I agree that it would be nice if the enums had a Length property. I
also agree that it would be nice if it had an IndexOf function for
getting the location of an item in the enum. That might reduce the
confusion about casting to an int.

My big beef with the enums in C#, though, is that declaring the type
on them doesn't actually change the output type! You can declare
"enum : byte { ed, coed}" but then when you use it you still have to
cast it to a byte. That's lame. I should be able to make an enum out
of any type. If the type doesn't have an implicit or explicit cast
from integer, then it should make me fill in a value on every entry
with the appropriate type. But it should still work, dang it, and I
shouldn't have to cast the output type. I guess I'd like to see it
treated more like a named array.
 
A

Arne Vajhøj

Jon said:
The problem with that is that array indexes are always integers.

No. That is just a C/C++/Java/C# way of doing it.

In Pascal, Ada etc. it is common to use enums as array indexes.

In the end it will of course become an offset into memory.

But it encapsulates the enum->offset calculation nicely.

Arne
 
A

Arne Vajhøj

Jon said:
That screams to me "Dictionary" - array is (logically) just a special
type of map which always uses ints as the key. At the point where you
want to use a type *other* than int, you should use the more general
form. It will give you additional type safety by not only *allowing*
you to use the enum, but *forcing* you to.

Declaring an array index to be of type enum in Pascal or Ada also
forces you to use a variable of that type as index.

You can simulate the functionality using Dictionary<,>, but that
does not provide the bound check functionality.

Unless you implement an Enum class a la Java enum and use that as key.

Arne
 
A

Arne Vajhøj

Jon said:
Does
Pascal allow enums to have proper behaviour though, in the same way as
Java enums do?

If you by "Java way" just means "not a camouflaged int" then yes.

But besides that they do not share much. Pascal (in its traditional
form) is procedural not object oriented. And it has the whole
strongly typed alias'es type concept. Different world.

Arne
 
A

Arne Vajhøj

not_a_commie said:
My big beef with the enums in C#, though, is that declaring the type
on them doesn't actually change the output type! You can declare
"enum : byte { ed, coed}" but then when you use it you still have to
cast it to a byte.

Not having to do that would make it even more type unsafe.

Arne
 
J

Jon Skeet [C# MVP]

Arne Vajhøj said:
If you by "Java way" just means "not a camouflaged int" then yes.

Well, I meant allowing them to behave like proper objects - with
constructors, inheritance, defining their own methods etc. A restricted
set of values of (or derived from) a particular type, basically.
But besides that they do not share much. Pascal (in its traditional
form) is procedural not object oriented. And it has the whole
strongly typed alias'es type concept. Different world.

That gets rid of a fair amount then, really. What about Delphi?
 
A

Arne Vajhøj

Jon said:
Well, I meant allowing them to behave like proper objects - with
constructors, inheritance, defining their own methods etc. A restricted
set of values of (or derived from) a particular type, basically.


That gets rid of a fair amount then, really. What about Delphi?

I am not an expert in Delphi, but I believe Delphi is a superset
of Pascal and that Delphi enumerations is identical to standard
Pascal enumerations.

Arne
 
I

Ian Semmel

No, the language *defines* an ordinal set.


No it doesn't - it assumes knowledge of the C# language specification,
which lays it out very clearly. No compiler internals are required.

Mathematically it's meaningless. We have designed what is effectively a
set of Fruit, and have got something which is outside the set. It takes
the object-orientedness out of the language allowing integer
manipulation of enums.

What C# enums are is essentially

static int apples = 0;
static int oranges = 1;

which is probably better because we can then just say arrayitem [
oranges ] without the type casts etc

Perhaps when C## comes out, we will be able to have sets and associated
algorithms

eg set_of_Fruit s;

if oranges in s

etc
 
J

Jon Skeet [C# MVP]

Ian Semmel said:
Mathematically it's meaningless. We have designed what is effectively a
set of Fruit, and have got something which is outside the set. It takes
the object-orientedness out of the language allowing integer
manipulation of enums.

Agreed. That doesn't mean it assumes knowledge of the compiler though.
What C# enums are is essentially

static int apples = 0;
static int oranges = 1;

which is probably better because we can then just say arrayitem [
oranges ] without the type casts etc

The difference is that if you have two enums, say Fruit and Vehicle, it
won't let you say:

Fruit f = Vehicle.Car;
or
Vehicle v = Fruit.Apple;

As an example of where this is important, consider the parameters to
this FileStream constructor overload:

FileStream(string, FileMode, FileAccess)

If the FileMode and FileAccess enumerations were just integers with no
extra type information, it would be really easy to get them the wrong
way round. As it is, the compiler will complain. I like that.
Perhaps when C## comes out, we will be able to have sets and associated
algorithms

eg set_of_Fruit s;

if oranges in s

You can do that today with either Dictionary<K,V> or (preferrably, but
only using .NET 3.5) HashSet<T>. Yes, you have to use a library instead
of it being built into the language - but that's not so bad really.

Don't get me wrong - I'd love to have more support for enums, making
them properly object oriented. I just don't see arrays or the lack of
implicit conversions as being the problem with them.
 
A

Arne Vajhøj

Jon said:
Don't get me wrong - I'd love to have more support for enums, making
them properly object oriented. I just don't see arrays or the lack of
implicit conversions as being the problem with them.

Having array index being defined as types (enums or integer subtypes)
would convert a lot of IndexOutOfRangeException's to compile time
errors.

Arne
 
J

Jon Skeet [C# MVP]

Arne Vajhøj said:
Having array index being defined as types (enums or integer subtypes)
would convert a lot of IndexOutOfRangeException's to compile time
errors.

Really "a lot"? How often is this happening to you? I can't remember
*ever* having this problem - not a single time. I very, very rarely
want to create an array mapping an enum to something else. Usually if I
do want such a map, I'll use a Dictionary<K,V> in the first place.
 
B

Barry Kelly

Jon said:
Well, I meant allowing them to behave like proper objects - with
constructors, inheritance, defining their own methods etc. A restricted
set of values of (or derived from) a particular type, basically.

Pascal enums define a set of new ordinal values. They're not object
oriented, but they are more strongly typed than CLR enums. It's
reasonably common in Pascal to define an array indexed by an enum, which
is basically what the original poster is after:

type
MyEnum = (enFoo, enBar, enBaz);
MyArray = array[MyEnum] of string;

I believe the root of the relative deficiency in C# is similar to the
early warnings about use of 'const', and the lack of default arguments
in C#, because these things burn values into user expressions and
callsites, rather than leaving things late-bound.

I believe it's all part of the general orientation in C# towards not
breaking code by upgrading components (cf. odd overloading rules in C#
when interacting with inheritance, for example).
That gets rid of a fair amount then, really. What about Delphi?

The above is pretty much the same in Delphi, apart from scoped
enumerations in Delphi for .NET - one can use MyEnum.enFoo, or
preferably drop the conventional 'xx' enum value prefix altogether.

As a bonus, in Delphi for Win32, one can use {$SCOPEDENUMS ON} to enable
the same behaviour. I implemented it soon after joining CodeGear.

-- Barry
 
B

Barry Kelly

Lasse said:
Ian said:
If I have

Enum en
{
i1,
i2,
i3
}

I reckon I should be able to have

int[] v = new int [ en ];

It is obvious what I want to do, but the compiler doesn't like it.

The only way I know to do it is (is there a better way?)

v = new int[ Enum.GetValues( typeof ( en) ).GetLength (0) ];

.NET arrays are indexed arrays, not associative arrays. The only way you
can index an array in .NET is through an integer, which is why the
compiler doesn't like you trying to use an enum as its index.

Enums are ordinal types, so arrays indexed by ordinals (e.g. Pascal) are
not normally associative arrays. Below the language level, they have
usually have exactly the same implementation.

-- Barry
 
B

Barry Kelly

Lew said:
The C# enum is a "poor cousin", just because it won't break type safety for
your convenience?

Lew, using an enum as the ordinal type for indexing an array doesn't
compromise type safety, and it can even increase it.

It's not idiomatic C# to index arrays with enum types, but the reasons
behind that are related to late binding, IMO, not type safety.

I believe the concern was something like this: consider some assembly A
defining some enum A.E. Another assembly B tries to create an array
indexed by E. Replace assembly A with A`, with a new version of A.E,
A.E`, and now assembly B is in a pretty poor state.

However, anyone who has used switch statements knows (or should know)
that introducing new enum values can still be problematic.

-- Barry
 
B

Barry Kelly

Jon said:
The problem with that is that array indexes are always integers.

How can you index some array with an arbitrary object? You can associate an
object with an array element but that is different.

Enums are not arbitrary objects. The value of a variable of an enum type
is a singular atom drawn from a countable ordered set. It can be
trivially converted into an integer during compilation; similarly,
arrays declared as indexed by an enum have well-defined size, and are
not like associative arrays implemented via hash tables.

-- Barry
 
L

Lew

Barry said:
Lew, using an enum as the ordinal type for indexing an array doesn't
compromise type safety, and it can even increase it.

It's not idiomatic C# to index arrays with enum types, but the reasons
behind that are related to late binding, IMO, not type safety.

I believe the concern was something like this: consider some assembly A
defining some enum A.E. Another assembly B tries to create an array
indexed by E. Replace assembly A with A`, with a new version of A.E,
A.E`, and now assembly B is in a pretty poor state.

However, anyone who has used switch statements knows (or should know)
that introducing new enum values can still be problematic.

Yes, I see the point you and Arne made. Thanks.
 
A

Arne Vajhøj

Jon said:
Really "a lot"? How often is this happening to you? I can't remember
*ever* having this problem - not a single time.

You have never seen an IndexOutOfRangeException ??
I very, very rarely
want to create an array mapping an enum to something else. Usually if I
do want such a map, I'll use a Dictionary<K,V> in the first place.

In languages that support array over enum they are used rather
frequently.

Different style of programming.

Arne
 
J

Jon Skeet [C# MVP]

Arne Vajhøj said:
You have never seen an IndexOutOfRangeException ??

Never where an enum would have solved the issue.
In languages that support array over enum they are used rather
frequently.

Different style of programming.

I don't see what's so different here, other than what construct you use
to solve the same problem: just use a Dictionary<K,V> instead of an
array. Why get hung up on the details of the solution? The *style* is
still the same, IMO.
 
A

Arne Vajhøj

Jon said:
Never where an enum would have solved the issue.

OK.

But situations with IOORE on array indexes that are small and
fixed do happen.
I don't see what's so different here, other than what construct you use
to solve the same problem: just use a Dictionary<K,V> instead of an
array. Why get hung up on the details of the solution? The *style* is
still the same, IMO.

The semantics are not the same - non init'ed values, rvalue/lvalue,
poor runtime check.

And I suspect that performance would not be the same either.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top