Rationale behind int to enum casts

A

Andreas Huber

Hi there

Spending half an hour searching through the archive I haven't found a
rationale for the following behavior.

using System;

// note the missing Flags attribute
enum Color
{
Red,
Green,
Blue
}

class Whatever
{
static void Main()
{
// The following cast succeeds although the
// value 42 does not exist.
Color color = (Color) 42;
Console.WriteLine( "{0}", color );
}
}

I believe it would make my and other peoples life easier if that cast
failed. Moreover, the framework does not even seem to offer a function
to implement this directly. I have to roll my own, using
Enum.IsDefined().

What is the rationale for this?

Thanks & Regards,

Andreas
 
M

Miha Markic

Hi Andreas,

Your enum is really an int.
And the framework won't look if it is defined or not because of performance
issue.
Imagine this

enum Tubo
{
Alfa = 11,
Beta = 44
}

public void SomeMethod(int j)
{
int i = 5 * j;
Tubo t = (Tubo)i;
}

It would be a big performance hit if runtime checks if it is valid or not...
 
C

Christoph Nahr

It would be a big performance hit if runtime checks if it is valid or not...

Only if you constantly convert from int to enum which you shouldn't be
doing anyway because it defeats the point of having enums in the first
place. At least in debug mode, the compiler or framework should check
automatically that the value is actually valid.

Again, the whole point of using enums instead of ints is type safety.
I agree with Andreas that this behaviour is bizarre and should be
fixed, performance hit or not.
 
U

Uwe Hafner

Hi,

Christoph Nahr said:
I agree with Andreas that this behaviour is bizarre and should be
fixed, performance hit or not.

There is nothing to "fix". This is a documented behaviour.

From MSDN:
MSDN .NET Framework General Reference
Value Type Usage Guidelines

<quote>
Do not assume that enum arguments will be in the defined range. It is valid
to cast any integer value into an enum even if the value is not defined in
the enum. Perform argument validation as illustrated in the following code
example.
[Visual Basic]
Public Sub SetColor(newColor As Color)
If Not [Enum].IsDefined(GetType(Color), newColor) Then
Throw New ArgumentOutOfRangeException()
End If
End Sub
[C#]
public void SetColor (Color color)
{
if (!Enum.IsDefined (typeof(Color), color)
throw new ArgumentOutOfRangeException();
}
</quote>

hth
Uwe
 
E

Eric Gunnerson [MS]

Enums are used both for a set of enumerated values, and for bit fields. In
the bit fields case, you need to be able to represent values that aren't
equal to one of the defined constants.

You can use the static methods on the Enum class to see if a specific value
is equal to one of the predefined constant values.

--
Eric Gunnerson

Visit the C# product team at http://www.csharp.net
Eric's blog is at http://blogs.gotdotnet.com/ericgu/

This posting is provided "AS IS" with no warranties, and confers no rights.
 
C

Christoph Nahr

There is nothing to "fix". This is a documented behaviour.

Yes... we disagree with that documented behaviour, and consider it
broken, hence we want a "fix".
 
C

Christoph Nahr

Enums are used both for a set of enumerated values, and for bit fields. In
the bit fields case, you need to be able to represent values that aren't
equal to one of the defined constants.

But bit field enums are always indicated by the [Flags] attribute,
correct? It should be easy enough to auto-generate a conversion check
if that attribute is not present.
 
M

Miha Markic

Hi Chris,

Christoph Nahr said:
Enums are used both for a set of enumerated values, and for bit fields. In
the bit fields case, you need to be able to represent values that aren't
equal to one of the defined constants.

But bit field enums are always indicated by the [Flags] attribute,
correct? It should be easy enough to auto-generate a conversion check
if that attribute is not present.

Not really.
FlagsAttribute is just a descriptor - used by some function (for text output
(ToString) if I remember correctly).
You can safely use enums for flags without FlagsAttribute.
 
A

Andreas Huber

Eric,
Enums are used both for a set of enumerated values, and for bit fields. In
the bit fields case, you need to be able to represent values that aren't
equal to one of the defined constants.

I know, I'm wondering why C# behaves this way __even if I don't put a
Flags attribute__ on my enum. This doesn't make a lot of sense to
me...

Thanks & Regards,

Andreas
 
M

Matt

I believe it would make my and other peoples life easier if that cast
failed. Moreover, the framework does not even seem to offer a function
to implement this directly. I have to roll my own, using
Enum.IsDefined().

I had a similar discussion about this a while back, so the following
may be of interest to you:
http://groups.google.com/[email protected]
[watch out for wordwrap]

Regards,

Matt
 
C

Christoph Nahr

FlagsAttribute is just a descriptor - used by some function (for text output
(ToString) if I remember correctly).
You can safely use enums for flags without FlagsAttribute.

Okay, but who does this? IMO it would be safe to restrict the language
definition so that Flags is required for bitwise combinable flags. The
compiler could then react to the absence of the attribute by providing
a custom base-type-to-enum conversion with range-checking code.
 
D

Daniel O'Connell

Christoph Nahr said:
Okay, but who does this? IMO it would be safe to restrict the language
definition so that Flags is required for bitwise combinable flags. The
compiler could then react to the absence of the attribute by providing
a custom base-type-to-enum conversion with range-checking code.

Which is fine until you have to use a VB, or C++, or any other language
library and cannot perform bitwise combinations because that language
doesn't force the Flags attribute. It cannot be a single langauge thing, it
would have to be defined in the CLS. If you cannot rely on your enums being
created IN C#, so you cannot rely on a language specification to handle this
situation, the runtime and all assocaited languages would have to use it.
And I personally don't want to have to cast every enum to int to perform a
bitwise operation and cast back to the enum.
Frankly, I consider the lack of member value checking a nicety. There are
times when using a bit flagged set of options where you will have flags set
that aren't considred in the current version, but are irrelevent and can be
ignored, having to write code to mask out all possible invalid flags is a
pain and will result in incorrect flags set when persisted.
 
A

Andreas Huber

Daniel,
Which is fine until you have to use a VB, or C++, or any other language
library and cannot perform bitwise combinations because that language
doesn't force the Flags attribute. It cannot be a single langauge thing, it
would have to be defined in the CLS.

Easy: Enums lacking a Flags attribute would not be CLS compliant. It's
the same situation with unsigned/signed ints: The whole .NET framework
uses only signed ints. However, C#-only stuff can use unsigned ints,
which means that such code cannot be consumed by languages like VB.

Of course the CLR would have to support two types of enums:
- A strict one that is always checked and thus only usable for
ordinary enums.
- A nonstrict one that is never checked and thus usable for both
ordinary and bitflagged enums.
Depending on the language, either the strict or the non-strict one is
emitted by default. In C# this would be the strict variant, adding a
Flags attribute would make it a non-strict one what also makes it
consumeable by other languages.
And I personally don't want to have to cast every enum to int to perform a
bitwise operation and cast back to the enum.
Frankly, I consider the lack of member value checking a nicety. There are
times when using a bit flagged set of options where you will have flags set
that aren't considred in the current version, but are irrelevent and can be
ignored, having to write code to mask out all possible invalid flags is a
pain and will result in incorrect flags set when persisted.

The checking would only be done for enums lacking the Flags attribute,
enums with the Flags attribute would not be checked. This way the
programmer has full control.

Regards,

Andreas
 
D

Daniel O'Connell

Andreas Huber said:
Daniel,


Easy: Enums lacking a Flags attribute would not be CLS compliant. It's
the same situation with unsigned/signed ints: The whole .NET framework
uses only signed ints. However, C#-only stuff can use unsigned ints,
which means that such code cannot be consumed by languages like VB.

Of course the CLR would have to support two types of enums:
- A strict one that is always checked and thus only usable for
ordinary enums.
- A nonstrict one that is never checked and thus usable for both
ordinary and bitflagged enums.
Depending on the language, either the strict or the non-strict one is
emitted by default. In C# this would be the strict variant, adding a
Flags attribute would make it a non-strict one what also makes it
consumeable by other languages.

Since an enum is an int(or other basic type) at its heart, you can't even
guarentee it was generated in a .NET language. The int easly could be
produced by unmanaged C++, VB6, TSQL, Delphi, Assembly, SmallTalk, whatever,
and stored in a database. Its not always possible to assume the enum was
sourced from .NET, it adds another point of failure to your application.
Plus, don't you think this is getting a little complex? Two enum types,
different rules, different rules for the flag type...I thought part of the
point of C# was to avoid the insane amount of uselss complexity C++ hoisted
on us. This would not exact help simplicity. There could also be a set of
complex rule attributes specifying that value a can only be set if value b
isn't, etc, but do we need that level of language complexity IN enums? I
don't hear anyone wanting that, and I think it would be far more useful.
The checking would only be done for enums lacking the Flags attribute,
enums with the Flags attribute would not be checked. This way the
programmer has full control.

Which would result in ALOT of enums being marked as Flags(or an unstrict
attribute) because the programmer cannot allow member checking in his
situtation, either because they need an empty state in the enum or the enum
value is generated outside of the runtime. Again, even assuming new CLS
rules, any time the enum value is produced outside of an enum, you cannot
assume that enum value is valid and therefore would either a) have to check
it before casting to enum, b) risk suffering an exception from not checking
it, thereby slowing down or possibly breaking code. I don't think I want to
have to write a try{} block around every enum assignement I do, and doing my
own checking defeats the purpose of the runtime performing the checks for
me.

I just don't want to have to write code like this(pseudocode):

MyEnum myEnum;
int enumValue = SomeoneElsesFunctionThatReturnsInt();
//I'd rather not get a surprise exception, why waste the cycles?
//not to mention, the code would be identical if the runtime did no checks
if (MyEnum.IsDefined(enumValue))
myEnum = (MyEnum)enumValue;
else
myEnum = MyEnum.Default;
where the system assignement to myEnum basically does this:

if (MyEnum.IsDefined(value))
return new myEnum;
else
throw new InvalidEnumValueException();

Why do we need two calls to IsDefined here? I mean, in the end this will
just result in slower code all around and probably more errors. Is there
really any benefit if I still have to check the value before casting to
avoid a useless exception? Considering, in this case, the range of
non-exceptional values is finite, avoiding the exception would be
responsible, imho. So exception or no, you will have to do the check if you
want to write decent code...what is the benefit?
 
A

Andreas Huber

Daniel,
Since an enum is an int(or other basic type) at its heart, you can't even
guarentee it was generated in a .NET language. The int easly could be
produced by unmanaged C++, VB6, TSQL, Delphi, Assembly, SmallTalk, whatever,
and stored in a database. Its not always possible to assume the enum was
sourced from .NET,

I fail to see what the underlying layout of a class or an enum has to
do with invariant enforcement. Just like a class an enum is simply an
abstract concept, nothing more nothing less.
I also don't to see why the source of an object (data base, file,
interlanguage call, etc.) should have an impact on whether the
invariants should be enforced or not.
When I save an enum into an external store and reload it later, I'll
just as much expect that the enum will have a legal value as I expect
an object of *any* other type to have a legal value. E.g. If I convert
a string into a DateTime object I'll expect that the object is in a
legal state after conversion or an exception being thrown otherwise.
And this is exactly what DateTime.Parse() does.
Why should an int to enum conversion behave differently than a string
to DateTime conversion? In both cases the problem is the same: that an
object of the source type has many more legal states than an object of
the destination type.
it adds another point of failure to your application.

From what you have written so far, I assume that you would simply
allow the invalid enum value be processed and/or displayed by your
program. While I can imagine situations where it is perfectly
reasonable to do so (ignoring a problem and grinding on rather than
dealing with it), I don't think that this is good practice in most
real-world applications. The reasons are as follows:

- Most people prefer a program that refuses to perform an operation
when it detects a problem over a program that produces incorrect
results. This is/was the case in all projects I was involved in
- If you allow enums to have invalid values your *whole* program must
be able to deal with them, i.e. similar code must be spread
everywhere. I'd rather avoid this when I can make the checks once,
i.e. in the persistence or interfacing layer
Plus, don't you think this is getting a little complex? Two enum types,
different rules, different rules for the flag type...I thought part of the
point of C# was to avoid the insane amount of uselss complexity C++ hoisted
on us.

Well, the world is complex, isn't it ;-)? Seriously, wasn't the single
most important argument for C# and .NET that the code is managed, i.e.
that many common programmer errors can and will be detected by the
runtime?
I'll ignore the C++ part for the moment as that would be worth a
thread of its own.
This would not exact help simplicity. There could also be a set of
complex rule attributes specifying that value a can only be set if value b
isn't, etc, but do we need that level of language complexity IN enums? I
don't hear anyone wanting that, and I think it would be far more useful.

What is so complex about having to put a Flags attribute on an enum
that you don't want to have checked? Plus, either the compiler could
help you in many situations or you'd find out very soon when you test
your code for the first time. How this is implemented is of little
importance.
Which would result in ALOT of enums being marked as Flags(or an unstrict
attribute) because the programmer cannot allow member checking in his
situtation, either because they need an empty state in the enum or the enum
value is generated outside of the runtime.

If you need an empty state, give the enum one. Period. I still fail to
see what the enum value being generated outside the runtime has to do
with invariant enforcement.
Again, even assuming new CLS
rules, any time the enum value is produced outside of an enum, you cannot
assume that enum value is valid and therefore would either a) have to check
it before casting to enum, b) risk suffering an exception from not checking
it, thereby slowing down or possibly breaking code.

This is such a common misconception. Why do you check the enum to
avoid the exception? As you can expect the exception to only be thrown
very rarely, the checking to avoid the exception will actually slow
the code down, because try blocks are a lot faster than ifs, as long
as no exception is thrown.
I don't think I want to
have to write a try{} block around every enum assignement I do, and doing my
own checking defeats the purpose of the runtime performing the checks for
me.
Dito.

I just don't want to have to write code like this(pseudocode):

MyEnum myEnum;
int enumValue = SomeoneElsesFunctionThatReturnsInt();
//I'd rather not get a surprise exception, why waste the cycles?
//not to mention, the code would be identical if the runtime did no checks
if (MyEnum.IsDefined(enumValue))
myEnum = (MyEnum)enumValue;
else
myEnum = MyEnum.Default;
where the system assignement to myEnum basically does this:

if (MyEnum.IsDefined(value))
return new myEnum;
else
throw new InvalidEnumValueException();

Why do we need two calls to IsDefined here? I mean, in the end this will
just result in slower code all around and probably more errors.

We don't! See above.
Is there
really any benefit if I still have to check the value before casting to
avoid a useless exception? Considering, in this case, the range of
non-exceptional values is finite, avoiding the exception would be
responsible, imho. So exception or no, you will have to do the check if you
want to write decent code...what is the benefit?

And I claim exactly the opposite, decent code never checks to avoid
exceptions that occur only rarely.
Moreover such errors (an enum having an invalid value) can almost
never be dealt with locally. More often than not the error has to be
passed up the call chain over several stack frames. This is exactly
what exceptions were invented for.

Regards,

Andreas
 
D

Daniel O'Connell

Andreas Huber said:
Daniel,


I fail to see what the underlying layout of a class or an enum has to
do with invariant enforcement. Just like a class an enum is simply an
abstract concept, nothing more nothing less.
I also don't to see why the source of an object (data base, file,
interlanguage call, etc.) should have an impact on whether the
invariants should be enforced or not.
When I save an enum into an external store and reload it later, I'll
just as much expect that the enum will have a legal value as I expect
an object of *any* other type to have a legal value. E.g. If I convert
a string into a DateTime object I'll expect that the object is in a
legal state after conversion or an exception being thrown otherwise.
And this is exactly what DateTime.Parse() does.

And they are introducing DateTime.TryParse() for just that reason, sometimes
an exception is just not acceptable.
Why should an int to enum conversion behave differently than a string
to DateTime conversion? In both cases the problem is the same: that an
object of the source type has many more legal states than an object of
the destination type.


From what you have written so far, I assume that you would simply
allow the invalid enum value be processed and/or displayed by your
program. While I can imagine situations where it is perfectly
reasonable to do so (ignoring a problem and grinding on rather than
dealing with it), I don't think that this is good practice in most
real-world applications. The reasons are as follows:

- Most people prefer a program that refuses to perform an operation
when it detects a problem over a program that produces incorrect
results. This is/was the case in all projects I was involved in
- If you allow enums to have invalid values your *whole* program must
be able to deal with them, i.e. similar code must be spread
everywhere. I'd rather avoid this when I can make the checks once,
i.e. in the persistence or interfacing layer
It would depend on what the enums meaning was. If the enum specified an
operation, or a list entry, etc, then no I wouldn't. However, if it is just
an option and no option is as valid as all options, then yes I would. When I
load an enum, if the enum must have a value I do the checking. If it is
acceptable for it to be empty(granted, these are usually Flags decorated
enums), then I leave it be.
Well, the world is complex, isn't it ;-)? Seriously, wasn't the single
most important argument for C# and .NET that the code is managed, i.e.
that many common programmer errors can and will be detected by the
runtime?
Yes, followed closely by increased simplicity.
I'll ignore the C++ part for the moment as that would be worth a
thread of its own.


What is so complex about having to put a Flags attribute on an enum
that you don't want to have checked? Plus, either the compiler could
help you in many situations or you'd find out very soon when you test
your code for the first time. How this is implemented is of little
importance.

Its semantically wrong, IMHO, to use Flags on an enum that is not a flagged.
I'd argue for a Unchecked attribute before I'd accept using Flags on a
non-flagged enum.
If you need an empty state, give the enum one. Period. I still fail to
see what the enum value being generated outside the runtime has to do
with invariant enforcement.

While thats preferable, it doesn't mean its always possible or it is always
done(not all enums in the world are under my control, for example)
This is such a common misconception. Why do you check the enum to
avoid the exception? As you can expect the exception to only be thrown
very rarely, the checking to avoid the exception will actually slow
the code down, because try blocks are a lot faster than ifs, as long
as no exception is thrown.

Because if I did not generate the enum value, there is NO reason to assume
the exception will be uncommon. If the enum is sourced by a non .NET
language or whatever, there is no way to assume it is correct. Just as if
you were given a file name, do you jsut open the file and catch the
exception if it comes? or do you call File.Exists() to check while still
handling exceptions as they come.
It depends heavily on the context, IMHO. If you are dealing with ONE file,
then just relying on the exception is ok, if you are dealing with many, you
have no idea how common the issue will be and cannot rely on the exception
being rare. It could happen 500000 times, you cannot tell at runtime.
In most cases, I consider enums to be singlar operations, but then again, in
most cases I consider files to be singlar operations too. This change could
potentially seriously cut back on flexibility.
We don't! See above.


And I claim exactly the opposite, decent code never checks to avoid
exceptions that occur only rarely.
Moreover such errors (an enum having an invalid value) can almost
never be dealt with locally. More often than not the error has to be
passed up the call chain over several stack frames. This is exactly
what exceptions were invented for.
I agree, I just don't think the runtime should be throwing the exception. If
there is need for an exception to be thrown, I'll do it. I wrote the code
and at times the runtime is a bit too invasive as it is, this would just
make it more so. There is a line where features for the common start to make
it too difficult to work in the environment for the uncommon, I think this
feature would be one. It would make .NET a much less interesting choice in
enough situations that it would dilute its value to me.

Perhaps an Enum static method equivilent to the DateTime method ParseExact
would be more appropriate? While it wouldn't be called ParseExact,
obviously, as it doesn't deal with strings, but it seems like it would solve
this problem without an issue, allow casts to operate as is(breaking
existing functionality is also unattractive), and add a static member that
throws an exception if the enum value is incorrect, maybe something like

struct Enum
{
//existing enum members
//Performs the same work as a cast
public static object GetEnum(Type enumType, int value);
//Performs the same work as a cast, however checks the enum
//and insures value is a valid type.
public static object GetEnumExact(Type enumType, int value);
//other overloads for possible underlying types. Unfortunatly
//generics cannot take System.Enum as a type constraint, so you are stuck
with a cast

}
The main advantage of this is it would allow both Flags and non-Flags
decorated enums to be validly converted in either situation. It can be that
in one case a Flags enum needs to be precise, but in others needs to be
loose. A specific rule using Flags potentially causes loss of flexibility.
Adding another attribute to the mix fixes that, but adds more complexity and
locks the enum's use to what the author of the enum wants. In some cases the
author cannot know how exactly the enum will be used outside of it being
Flags or a singular enum, or the enum will be of value in another situation.
This will allow the consumer to determine the specifics and help
reuseability. The consumer would have to be responsible for making sure that
it doesn't call a method that expects valid enums without a try\catch
block(or appropriate handling) if the consumer doesn't validate the enum.
This is a situation where adding attributes to a given instance would be of
value, a ValidatedInstanceAttribute or something.
 
A

Andreas Huber

Daniel,
And they are introducing DateTime.TryParse() for just that reason, sometimes
an exception is just not acceptable.

An exception is only unacceptable, if you expect the
failed-calls/overall-calls ratio to be so high that performance may be
adversely affected. This also implies that you don't need to propagate
the error over many stack frames (if so then exceptions have a good
chance to outperform error-codes, not to mention the advantages of
exceptions concerning correctness). If a programmer uses TryParse in
such a situation then that's fine with me. However, I very much doubt
that (s)he could predict what that critical ratio is in the situation
at hand. I consider error-codes a fall-back that you only use when you
absolutely have to, i.e. when a profiler shows that exception
processing eats up significant amounts of the overall processor
cycles.
As for DateTime.TryParse(), yes I can imagine situations where you
really want to avoid that exception but are these situations so
common? I don't think so and neither does Microsoft as they would
otherwise have introduced TryParse() earlier. Note also that the
"default" function Parse() does throw exceptions.
It would depend on what the enums meaning was. If the enum specified an
operation, or a list entry, etc, then no I wouldn't. However, if it is just
an option and no option is as valid as all options, then yes I would. When I
load an enum, if the enum must have a value I do the checking. If it is
acceptable for it to be empty(granted, these are usually Flags decorated
enums), then I leave it be.

I would do exactly the same. Note that I'm not against means to make
unchecked enum conversions, it's just the default that I'm unhappy
with. I.e. I would like to see the cast throw exceptions but
Enum.ToObject and Enum.Parse can continue to work as they do today.
Most people will use the cast and so version problems, programmer
errors, etc. will surface very quickly.

[snip]
Its semantically wrong, IMHO, to use Flags on an enum that is not a flagged.
I'd argue for a Unchecked attribute before I'd accept using Flags on a
non-flagged enum.

That'd be perfectly fine with me. As I said, I only want *some* means
to implement strict enums. Moreover, I should be able to declare the
strict variant as default (see below).
While thats preferable, it doesn't mean its always possible or it is always
done(not all enums in the world are under my control, for example)

Agreed. However, I think this is a rare case. Moreover, you can always
define your own enum with all necessary states and convert between the
two.

[snip]
Because if I did not generate the enum value, there is NO reason to assume
the exception will be uncommon. If the enum is sourced by a non .NET
language or whatever, there is no way to assume it is correct.

We don't need to assume that it is correct, the only thing that
matters is whether it is *usually* correct or not (i.e. the
failed-calls/overall-calls ratio is low). Moreover, I have yet to see
a real-world program where bad-input detection is a performance issue
(I'd be very interested in an example). Bad input usually comes
directly from humans and I can't imagine a program where humans will
notice the difference in execution speed. Even if the input comes from
somewhere else e.g. the int in a DB then I'd say that the
*probability* to find a row with an incorrect value is normally really
low, even if the Db is filled by other programs written in other
languages. Moreover, as I mentioned earlier, finding such an incorrect
value often means that there is something seriously wrong that can
usually only be corrected by humans. In my current project (where I
have such a DB-int to enum conversion) I'd simply write an appropriate
log entry and then let the exception take the whole process down.
Whether that takes milliseconds or seconds is a non-issue.
Just as if
you were given a file name, do you jsut open the file and catch the
exception if it comes? or do you call File.Exists() to check while still
handling exceptions as they come.
It depends heavily on the context, IMHO. If you are dealing with ONE file,
then just relying on the exception is ok, if you are dealing with many, you
have no idea how common the issue will be and cannot rely on the exception
being rare. It could happen 500000 times, you cannot tell at runtime.
In most cases, I consider enums to be singlar operations, but then again, in
most cases I consider files to be singlar operations too. This change could
potentially seriously cut back on flexibility.

I'd always just try to open the file without checking because disk
operations tend to be orders of magnitude slower than anything that
can be done in the processor (including the throwing and catching of
an exception). This is also true for most other external sources (DB,
network, human, etc.)
Moreover, are you sure that there is a real-world application that
*usually* needs to try to open s..tloads of non-existent files?

[snip]
I agree, I just don't think the runtime should be throwing the exception. If
there is need for an exception to be thrown, I'll do it.

I'd could agree (although not fully) if this affected only relatively
experienced programmers in perfect project environments. However,
there are many many .NET newbies not knowing any better and most
projects get into more than one schedule-crunch where even the best
programmers become sloppy. In both cases people end up using casts. Of
course, the introduced bugs will surface eventually but determining
the cause is much more difficult then. Again, if a programmer made a
conscious decisition to use a non-throwing method then that's fine
with me. It's only the default I'm unhappy with.
Perhaps an Enum static method equivilent to the DateTime method ParseExact
would be more appropriate? While it wouldn't be called ParseExact,
obviously, as it doesn't deal with strings, but it seems like it would solve
this problem without an issue, allow casts to operate as is(breaking
existing functionality is also unattractive), and add a static member that
throws an exception if the enum value is incorrect, maybe something like

I agree that it's a bad idea to break with existing functionality.
However, this could also be implemented with a new compiler setting
(just like the one that determines whether to throw exceptions on
arithmetic under-/overflow).

[snip]
The main advantage of this is it would allow both Flags and non-Flags
decorated enums to be validly converted in either situation. It can be that
in one case a Flags enum needs to be precise, but in others needs to be
loose. A specific rule using Flags potentially causes loss of flexibility.
Adding another attribute to the mix fixes that, but adds more complexity and
locks the enum's use to what the author of the enum wants. In some cases the
author cannot know how exactly the enum will be used outside of it being
Flags or a singular enum, or the enum will be of value in another situation.

Maybe, but this is rather uncommon isn't it? I tend to define new
enums for such cases.

Regards,

Andreas
 
D

Daniel O'Connell

Andreas Huber said:
Daniel,
And they are introducing DateTime.TryParse() for just that reason, sometimes
an exception is just not acceptable.

An exception is only unacceptable, if you expect the
failed-calls/overall-calls ratio to be so high that performance may be
adversely affected. This also implies that you don't need to propagate
the error over many stack frames (if so then exceptions have a good
chance to outperform error-codes, not to mention the advantages of
exceptions concerning correctness). If a programmer uses TryParse in
such a situation then that's fine with me. However, I very much doubt
that (s)he could predict what that critical ratio is in the situation
at hand. I consider error-codes a fall-back that you only use when you
absolutely have to, i.e. when a profiler shows that exception
processing eats up significant amounts of the overall processor
cycles.
As for DateTime.TryParse(), yes I can imagine situations where you
really want to avoid that exception but are these situations so
common? I don't think so and neither does Microsoft as they would
otherwise have introduced TryParse() earlier. Note also that the
"default" function Parse() does throw exceptions.
It would depend on what the enums meaning was. If the enum specified an
operation, or a list entry, etc, then no I wouldn't. However, if it is just
an option and no option is as valid as all options, then yes I would. When I
load an enum, if the enum must have a value I do the checking. If it is
acceptable for it to be empty(granted, these are usually Flags decorated
enums), then I leave it be.

I would do exactly the same. Note that I'm not against means to make
unchecked enum conversions, it's just the default that I'm unhappy
with. I.e. I would like to see the cast throw exceptions but
Enum.ToObject and Enum.Parse can continue to work as they do today.
Most people will use the cast and so version problems, programmer
errors, etc. will surface very quickly.

[snip]
Its semantically wrong, IMHO, to use Flags on an enum that is not a flagged.
I'd argue for a Unchecked attribute before I'd accept using Flags on a
non-flagged enum.

That'd be perfectly fine with me. As I said, I only want *some* means
to implement strict enums. Moreover, I should be able to declare the
strict variant as default (see below).
the
enum

While thats preferable, it doesn't mean its always possible or it is always
done(not all enums in the world are under my control, for example)

Agreed. However, I think this is a rare case. Moreover, you can always
define your own enum with all necessary states and convert between the
two.

[snip]
Because if I did not generate the enum value, there is NO reason to assume
the exception will be uncommon. If the enum is sourced by a non .NET
language or whatever, there is no way to assume it is correct.

We don't need to assume that it is correct, the only thing that
matters is whether it is *usually* correct or not (i.e. the
failed-calls/overall-calls ratio is low). Moreover, I have yet to see
a real-world program where bad-input detection is a performance issue
(I'd be very interested in an example). Bad input usually comes
directly from humans and I can't imagine a program where humans will
notice the difference in execution speed. Even if the input comes from
somewhere else e.g. the int in a DB then I'd say that the
*probability* to find a row with an incorrect value is normally really
low, even if the Db is filled by other programs written in other
languages. Moreover, as I mentioned earlier, finding such an incorrect
value often means that there is something seriously wrong that can
usually only be corrected by humans. In my current project (where I
have such a DB-int to enum conversion) I'd simply write an appropriate
log entry and then let the exception take the whole process down.
Whether that takes milliseconds or seconds is a non-issue.

The best I can think of, a project I worked on about a year ago was
processing data files produced by a horridly buggy program(an apparently
rather old one which the company was unwilling to replace, even though it no
longer worked in their current situation). It would commonly pump out
invalid file names in the command file, or generate incorrect command
values. Of course, they didn't tell me this ahead of time, so I went ahead
and wrote against the (correct)test data they gave me, and when I went to
test it live, I found that the source could cause somewhere between 10% and
20% entries to be incorrect. So I was left with the task of making the
processor capable of handling all the possible invalid options, which meant
taking away exception handling in alot of cases where I could and using
manual checks, it wasn't acceptable to spend that much time processing
exceptions.
I don't know how often strange situations like that come up, I just know I
seem to find well more than my share of them.
I'd always just try to open the file without checking because disk
operations tend to be orders of magnitude slower than anything that
can be done in the processor (including the throwing and catching of
an exception). This is also true for most other external sources (DB,
network, human, etc.)
Moreover, are you sure that there is a real-world application that
*usually* needs to try to open s..tloads of non-existent files?

Well, the situation comes down in batch processing. If you have a list of
1000, 2000, 10000 files, the chances that 10 or 100 of them may not exist
isn't small, 10 or 100 exceptions isn't my kind of thing in that situation.
Also, the chances that the folder information is cached in memory is pretty
high, higher after the first call, assuming your not scanning across a huge
possible directory set. The call to File.Exists() should remove any disk
access required in the open call, otherwise the call to open the file would
take the same period of time.
Anyway, put enums in the same situation. Batch processing a huge collection
of basic entries, one member of which is a enum, if the exception from the
cast causes 1 second of delay, and there are many incorrect enums(that does
happen) what is the performance drain? This is a case where the value
matters, can be handled directly by the loader(just log a invalid entry and
move on). Granted a simple Try type method to load the enum and return false
if it fails would solve that problem as well.
[snip]
I agree, I just don't think the runtime should be throwing the exception. If
there is need for an exception to be thrown, I'll do it.

I'd could agree (although not fully) if this affected only relatively
experienced programmers in perfect project environments. However,
there are many many .NET newbies not knowing any better and most
projects get into more than one schedule-crunch where even the best
programmers become sloppy. In both cases people end up using casts. Of
course, the introduced bugs will surface eventually but determining
the cause is much more difficult then. Again, if a programmer made a
conscious decisition to use a non-throwing method then that's fine
with me. It's only the default I'm unhappy with.
Yeah, I can see where you are coming from, however there are a few issues.
For one, you still have to write verification code in your methods, because
enum isn't going to definatly be a correct value, as well as now it would be
a change of existing defaults, which as I've said, is an unpleasent thing. I
can't even be 100% sure my code won't collapse in the face of that change,
can you or anyone else? Currently, you would have to add try catch blocks to
every enum cast you do or risk an unexpected crash and burn.
I agree that it's a bad idea to break with existing functionality.
However, this could also be implemented with a new compiler setting
(just like the one that determines whether to throw exceptions on
arithmetic under-/overflow).
Still, that generates unexpected functionality to the experianced developer
if set on by default, and would be ignored by the new programmer if it was
set off.
[snip]
The main advantage of this is it would allow both Flags and non-Flags
decorated enums to be validly converted in either situation. It can be that
in one case a Flags enum needs to be precise, but in others needs to be
loose. A specific rule using Flags potentially causes loss of flexibility.
Adding another attribute to the mix fixes that, but adds more complexity and
locks the enum's use to what the author of the enum wants. In some cases the
author cannot know how exactly the enum will be used outside of it being
Flags or a singular enum, or the enum will be of value in another
situation.

Maybe, but this is rather uncommon isn't it? I tend to define new
enums for such cases.
It depends, for some things, replacing system enums is a bad idea, as it
seems to confuse people. I don't see any reason why there needs to be four
identical WindowState enums or whatever. For a third party library I'll
rarely reuse one, but I don't like the confusion included with providing an
identical, both by contents and its semantic usage, replacement to something
defined in the mscorlib or System assemblies. Beyond that, you can't always
ignore the uncommon, it seems they come up more commonly across the board
than it ever seems they could.
 

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