473,412 Members | 2,003 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,412 software developers and data experts.

Compiler resolves to wrong overloaded constructor or method

Is this a bug in the C# compiler or CLR runtime?

enum MyEnum { ZERO = 0, ONE = 1, TWO = 2 }
class Foo {
public Foo(string,object) { ... }
public Foo(string,MyEnum) { ... }
}

Foo f = new Foo("", 0); // Uses Foo(string,MyEnum) constructor instead of
Foo(string,object)
Foo f = new Foo("", 0.0); // Uses Foo(string,MyEnum) constructor instead
of Foo(string,object)
Foo f = new Foo("", (int)0); // Uses Foo(string,MyEnum) constructor
instead of Foo(string,object)
BUT
Foo f = new Foo("", 1 ); // Uses Foo(string,object)
Foo f = new Foo("", (object)(int)0 ); // Uses Foo(string,object) with
object type Int32
Foo f = new Foo("", (double)0.0 ); // Uses Foo(string,object)

Actual case was from a ADO.NET Data Provider's PrvParameter constructors!
Same issue came up resolving the various overloads of
PrvParameterCollection.Add!

Anybody else seen this?
Philippe
Nov 16 '05 #1
30 1685
Philippe,

Haven't seen it.

How do you know it's using the Foo(string,MyEnum) constructor when you do a
new Foo("",0)? Are you seeing this when you single-step through the code?
If not, you should single-step with the debugger to make sure what you think
is executing is really executing. If you single-step and *still* see this
behavior, then I would rule out a bug in the debug display (it's happened in
the past, in unpatched CLR 1.0) by putting DebugWriteLine() statements into
the constructors and making sure they really DO execute as the debugger
shows.

--Bob

"Philippe Bertrand" <my*****@ianywhere.com> wrote in message
news:10*************@corp.supernews.com...
Is this a bug in the C# compiler or CLR runtime?

enum MyEnum { ZERO = 0, ONE = 1, TWO = 2 }
class Foo {
public Foo(string,object) { ... }
public Foo(string,MyEnum) { ... }
}

Foo f = new Foo("", 0); // Uses Foo(string,MyEnum) constructor instead of Foo(string,object)
Foo f = new Foo("", 0.0); // Uses Foo(string,MyEnum) constructor instead of Foo(string,object)
Foo f = new Foo("", (int)0); // Uses Foo(string,MyEnum) constructor
instead of Foo(string,object)
BUT
Foo f = new Foo("", 1 ); // Uses Foo(string,object)
Foo f = new Foo("", (object)(int)0 ); // Uses Foo(string,object) with
object type Int32
Foo f = new Foo("", (double)0.0 ); // Uses Foo(string,object)

Actual case was from a ADO.NET Data Provider's PrvParameter constructors!
Same issue came up resolving the various overloads of
PrvParameterCollection.Add!

Anybody else seen this?
Philippe

Nov 16 '05 #2

"Philippe Bertrand" <my*****@ianywhere.com> wrote in message
news:10*************@corp.supernews.com...
Is this a bug in the C# compiler or CLR runtime?

enum MyEnum { ZERO = 0, ONE = 1, TWO = 2 }
class Foo {
public Foo(string,object) { ... }
public Foo(string,MyEnum) { ... }
}

Foo f = new Foo("", 0); // Uses Foo(string,MyEnum) constructor instead of Foo(string,object)
Foo f = new Foo("", 0.0); // Uses Foo(string,MyEnum) constructor instead of Foo(string,object)
Foo f = new Foo("", (int)0); // Uses Foo(string,MyEnum) constructor
instead of Foo(string,object)
BUT
Foo f = new Foo("", 1 ); // Uses Foo(string,object)
Foo f = new Foo("", (object)(int)0 ); // Uses Foo(string,object) with
object type Int32
Foo f = new Foo("", (double)0.0 ); // Uses Foo(string,object)

I reproduced it. Very odd, especially the difference in behavior between
0.0 and (double)0.0, since 0.0 is already a double.
Nov 16 '05 #3
hi philippe,

see 7.4.2.2 of the C# language specification.
Foo f = new Foo("", 0); // Uses Foo(string,MyEnum) constructor instead of
Foo(string,object)
there exists an implicit convertion between int and MyEnum.
see 6.1.3 of the C# lang specification.
Foo f = new Foo("", 0.0); // Uses Foo(string,MyEnum) constructor instead
of Foo(string,object)
there exists an implicit convertion between double and int
and MyEnum. see 6.1.3.
Foo f = new Foo("", (int)0); // Uses Foo(string,MyEnum) constructor
instead of Foo(string,object)
there exists an implicit convertion between int and MyEnum.
see 6.1.3.
BUT
Foo f = new Foo("", 1 ); // Uses Foo(string,object)
6.1.3 doesn't apply here.
Foo f = new Foo("", (object)(int)0 ); // Uses Foo(string,object) with
object type Int32
the cast forces Foo(string,object).
Foo f = new Foo("", (double)0.0 ); // Uses Foo(string,object)


the cast disables the implicit int promotion.
since no Foo(string,double) exists, the next bext
overloaded method is taken.

bye
rob
Nov 16 '05 #4
Robert,

Can you give correct links to C# spec? (I mean ECMA-334, 2nd ed. (december
2002)).

Alex.
see 7.4.2.2 of the C# language specification.

there exists an implicit convertion between int and MyEnum.
see 6.1.3 of the C# lang specification.

Nov 16 '05 #5
But that is ridiculous!

You are saying to users that for all but these two special constants, the
language behaves on way but for these two magic constants you have to
explicitly cast.

Being in the spec doesn't make it a good idea!

"Robert Jordan" <ro*****@gmx.net> wrote in message
news:cg*************@news.t-online.com...
hi philippe,

see 7.4.2.2 of the C# language specification.
Foo f = new Foo("", 0); // Uses Foo(string,MyEnum) constructor instead of Foo(string,object)
there exists an implicit convertion between int and MyEnum.
see 6.1.3 of the C# lang specification.
Foo f = new Foo("", 0.0); // Uses Foo(string,MyEnum) constructor instead of Foo(string,object)


there exists an implicit convertion between double and int
and MyEnum. see 6.1.3.
Foo f = new Foo("", (int)0); // Uses Foo(string,MyEnum) constructor
instead of Foo(string,object)


there exists an implicit convertion between int and MyEnum.
see 6.1.3.
BUT
Foo f = new Foo("", 1 ); // Uses Foo(string,object)


6.1.3 doesn't apply here.


Why would there be an implicit conversion between int and MyEnum for the
value 0 but not the value 1?

Note:
int i = 0;
Foo f = new Foo("", i ); // Uses Foo(stirng,object)

This section 6.1.3 seems an extremely bizzard exception!
Foo f = new Foo("", (object)(int)0 ); // Uses Foo(string,object) with
object type Int32


the cast forces Foo(string,object).
Foo f = new Foo("", (double)0.0 ); // Uses Foo(string,object)


the cast disables the implicit int promotion.
since no Foo(string,double) exists, the next bext
overloaded method is taken.


Why would the implicit conversion be disabled when casting (double)0.0 but
not when casting (int)0 ?

Philippe
Nov 16 '05 #6
Yes, I'm certain (resulting object state different and stepped through
code). See my reply to Robert Jordan for cause of this magic behaviour.

Philippe
Nov 16 '05 #7
Hi Alex,
Robert,

Can you give correct links to C# spec? (I mean ECMA-334, 2nd ed. (december
2002)).


13.1.3 Implicit enumeration conversions
(6.1.3 MSDN spec)

"An implicit enumeration conversion permits the decimal-integer-literal
0 to be converted to any enum-type"
14.4.2.1 Applicable function member
(7.4.2.2 MSDN spec)

Rob
Nov 16 '05 #8
Thank you!

Alex.
Nov 16 '05 #9
Hi Philippe,
You are saying to users that for all but these two special constants, the
language behaves on way but for these two magic constants you have to
explicitly cast.
There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".

Consider this:

if ((val & SomeEnum.Foo) == 0) {
}

W/out this rule, the bool expression has to
be written like:

if ((val & SomeEnum.Foo) == (SomeEnum)0) {
}

This is ugly!

Being in the spec doesn't make it a good idea!


Reading the specs is a good idea, too ;-)

Bye
Rob
Nov 16 '05 #10

"Robert Jordan" <ro*****@gmx.net> wrote in message
news:cg*************@news.t-online.com...
Hi Philippe,
You are saying to users that for all but these two special constants, the
language behaves on way but for these two magic constants you have to
explicitly cast.


There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".


Much like Dennis Ritchie wanted to avoid introducing a keyword for the null
pointer, when "0" worked so well :-) That was a horrifically bad decision:
look at any newsgroup for C or C++ beginners: wheneve the subject arises
it's clear that 90% of them don't understand that a null pointer and the
number zero are wholly different objects that happen to be spelled the same.
Likewise, a special constant no_flags_set (or some such) that's a member of
all flags-enabled enums would be much clearer.
Nov 16 '05 #11

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:Os**************@TK2MSFTNGP10.phx.gbl...

"Robert Jordan" <ro*****@gmx.net> wrote in message
news:cg*************@news.t-online.com...
Hi Philippe,
You are saying to users that for all but these two special constants,
the
language behaves on way but for these two magic constants you have to
explicitly cast.
There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".


Much like Dennis Ritchie wanted to avoid introducing a keyword for the
null pointer, when "0" worked so well :-) That was a horrifically bad
decision: look at any newsgroup for C or C++ beginners: wheneve the
subject arises it's clear that 90% of them don't understand that a null
pointer and the number zero are wholly different objects that happen to be
spelled the same. Likewise, a special constant no_flags_set (or some such)
that's a member of all flags-enabled enums would be much clearer.


I disagree. Adding an implicit value removes one possible value from all
enums AND it adds complexity to *EVERY* use of a flags based attribute
whereas 0 is only going to come into play in rare circumstances and it
removes the ability to provide a speciallly named NoFlags value.

Simply put, in virtually any situation where you try to pump in soemthing
you feel will be easier in one circumstance you will inevitably cause
complexity in other circumstances. In the null pointer circumstance, a null
keyword would probably be correct because null pointers are extremly
common(maybe the most common thing you'll see in non-arithmetic C), however
flagged enums are relativly rare and certainly don't warrent a keyword or
implicit behaviour of any kind.

Nov 16 '05 #12

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:Og*************@tk2msftngp13.phx.gbl...

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:Os**************@TK2MSFTNGP10.phx.gbl...

"Robert Jordan" <ro*****@gmx.net> wrote in message
news:cg*************@news.t-online.com...
Hi Philippe,

You are saying to users that for all but these two special constants,
the
language behaves on way but for these two magic constants you have to
explicitly cast.

There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".
Much like Dennis Ritchie wanted to avoid introducing a keyword for the
null pointer, when "0" worked so well :-) That was a horrifically bad
decision: look at any newsgroup for C or C++ beginners: wheneve the
subject arises it's clear that 90% of them don't understand that a null
pointer and the number zero are wholly different objects that happen to
be spelled the same. Likewise, a special constant no_flags_set (or some
such) that's a member of all flags-enabled enums would be much clearer.


I disagree. Adding an implicit value removes one possible value from all
enums


That would be true if it were a qualified name (MyEnum.no_flags_set), not
if, as I suggested, it's a language keyword.
AND it adds complexity to *EVERY* use of a flags based attribute whereas 0
is only going to come into play in rare circumstances and it removes the
ability to provide a speciallly named NoFlags value.
Why would it either add complexity (if you don't use it) or remove your
abiality to add a 0-valued member?

Simply put, in virtually any situation where you try to pump in soemthing
you feel will be easier in one circumstance you will inevitably cause
complexity in other circumstances.
In the null pointer circumstance, a null keyword would probably be correct
because null pointers are extremly common(maybe the most common thing
you'll see in non-arithmetic C), however flagged enums are relativly rare
and certainly don't warrent a keyword or implicit behaviour of any kind.


The current implicit behavior (that in effect zero is a member of every
enum, at least under some spellings of zero) is what I'd like to avoid.
Introducing an *explicit* constant that represents "no flags set" for each
enum removes it. It also makes it clear to the uninitiated

1. that something unusual is happening, and
2. how to look it up (under "no_flags_set")

The current situation looks like a bizarre compiler error unless you're
familiar with the precise place in the spec that describes it.
Nov 16 '05 #13

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:eE**************@TK2MSFTNGP11.phx.gbl...

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:Og*************@tk2msftngp13.phx.gbl...

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:Os**************@TK2MSFTNGP10.phx.gbl...

"Robert Jordan" <ro*****@gmx.net> wrote in message
news:cg*************@news.t-online.com...
Hi Philippe,

> You are saying to users that for all but these two special constants,
> the
> language behaves on way but for these two magic constants you have to
> explicitly cast.

There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".

Much like Dennis Ritchie wanted to avoid introducing a keyword for the
null pointer, when "0" worked so well :-) That was a horrifically bad
decision: look at any newsgroup for C or C++ beginners: wheneve the
subject arises it's clear that 90% of them don't understand that a null
pointer and the number zero are wholly different objects that happen to
be spelled the same. Likewise, a special constant no_flags_set (or some
such) that's a member of all flags-enabled enums would be much clearer.
I disagree. Adding an implicit value removes one possible value from all
enums


That would be true if it were a qualified name (MyEnum.no_flags_set), not
if, as I suggested, it's a language keyword.


That is what I took you as meaning, yes.
AND it adds complexity to *EVERY* use of a flags based attribute whereas
0 is only going to come into play in rare circumstances and it removes
the ability to provide a speciallly named NoFlags value.
Why would it either add complexity (if you don't use it) or remove your
abiality to add a 0-valued member?

Because if it is a member of a given enum, its plain silly. I would have
other issues with a special keyword.

Simply put, in virtually any situation where you try to pump in soemthing
you feel will be easier in one circumstance you will inevitably cause
complexity in other circumstances.
In the null pointer circumstance, a null keyword would probably be
correct because null pointers are extremly common(maybe the most common
thing you'll see in non-arithmetic C), however flagged enums are
relativly rare and certainly don't warrent a keyword or implicit
behaviour of any kind.
The current implicit behavior (that in effect zero is a member of every
enum, at least under some spellings of zero) is what I'd like to avoid.
Introducing an *explicit* constant that represents "no flags set" for each
enum removes it. It also makes it clear to the uninitiated


It removes it at the cost of a new keyword(which users need to know). As it
stands there is only about three keywords that are very rarely used, yet
each has some value. Two of which, unsafe and fixed, make sense. The third,
stackalloc, could probably have been written as an API function or a
function of new, each other keyword has a practical common usage.
I don't think drawing a line between null pointers and unintialized enums is
a particularly valid point, either. As I showed before, null pointers are
more common and the constant 0 just isn't *that* common in code. In much of
my code there are no constants written into code, they instead are fields
which I reference(for clarities sake, I also tend to not use const,
prefering to take the potential performance hit and use readonly).

1. that something unusual is happening, and
2. how to look it up (under "no_flags_set")

The current situation looks like a bizarre compiler error unless you're
familiar with the precise place in the spec that describes it.


I would have prefered explicit casting, personally, but I don't think
learning the implicit case is terribly hard.
Nov 16 '05 #14

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:eX**************@tk2msftngp13.phx.gbl...

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:eE**************@TK2MSFTNGP11.phx.gbl...

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:Og*************@tk2msftngp13.phx.gbl...

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:Os**************@TK2MSFTNGP10.phx.gbl...

"Robert Jordan" <ro*****@gmx.net> wrote in message
news:cg*************@news.t-online.com...
> Hi Philippe,
>
>> You are saying to users that for all but these two special constants,
>> the
>> language behaves on way but for these two magic constants you have to
>> explicitly cast.
>
> There is no magic. The language designers wanted to avoid
> constructs like "(SomeEnum)0", because enums may be
> [Flags]-able, and thus they may be "0" w/out having
> a literal with the value "0".

Much like Dennis Ritchie wanted to avoid introducing a keyword for the
null pointer, when "0" worked so well :-) That was a horrifically bad
decision: look at any newsgroup for C or C++ beginners: wheneve the
subject arises it's clear that 90% of them don't understand that a null
pointer and the number zero are wholly different objects that happen to
be spelled the same. Likewise, a special constant no_flags_set (or some
such) that's a member of all flags-enabled enums would be much clearer.

I disagree. Adding an implicit value removes one possible value from all
enums
That would be true if it were a qualified name (MyEnum.no_flags_set), not
if, as I suggested, it's a language keyword.


That is what I took you as meaning, yes.


Then please explain how it removes a value from all enums.
AND it adds complexity to *EVERY* use of a flags based attribute whereas
0 is only going to come into play in rare circumstances and it removes
the ability to provide a speciallly named NoFlags value.


Why would it either add complexity (if you don't use it) or remove your
ability to add a 0-valued member?

Because if it is a member of a given enum, its plain silly. I would have
other issues with a special keyword.


Saying "it's silly" doesn't asnwer the question.
It removes it at the cost of a new keyword(which users need to know). As
it stands there is only about three keywords that are very rarely used,
yet each has some value. Two of which, unsafe and fixed, make sense. The
third, stackalloc, could probably have been written as an API function or
a function of new, each other keyword has a practical common usage.
I don't think drawing a line between null pointers and unintialized enums
is a particularly valid point, either.


Both are using "0" to mean something other than the integer 0. A bad idea.


Nov 16 '05 #15

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:e5*************@TK2MSFTNGP10.phx.gbl...

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:eX**************@tk2msftngp13.phx.gbl...

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:eE**************@TK2MSFTNGP11.phx.gbl...

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:Og*************@tk2msftngp13.phx.gbl...

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:Os**************@TK2MSFTNGP10.phx.gbl...
>
> "Robert Jordan" <ro*****@gmx.net> wrote in message
> news:cg*************@news.t-online.com...
>> Hi Philippe,
>>
>>> You are saying to users that for all but these two special
>>> constants, the
>>> language behaves on way but for these two magic constants you have
>>> to
>>> explicitly cast.
>>
>> There is no magic. The language designers wanted to avoid
>> constructs like "(SomeEnum)0", because enums may be
>> [Flags]-able, and thus they may be "0" w/out having
>> a literal with the value "0".
>
> Much like Dennis Ritchie wanted to avoid introducing a keyword for the
> null pointer, when "0" worked so well :-) That was a horrifically bad
> decision: look at any newsgroup for C or C++ beginners: wheneve the
> subject arises it's clear that 90% of them don't understand that a
> null pointer and the number zero are wholly different objects that
> happen to be spelled the same. Likewise, a special constant
> no_flags_set (or some such) that's a member of all flags-enabled enums
> would be much clearer.

I disagree. Adding an implicit value removes one possible value from
all enums

That would be true if it were a qualified name (MyEnum.no_flags_set),
not if, as I suggested, it's a language keyword.
That is what I took you as meaning, yes.


Then please explain how it removes a value from all enums.


Simple, if every enum gains a member "NoFlag" or whatever, then you are no
longer able to provide a "NoFlag" enum member of your own.

AND it adds complexity to *EVERY* use of a flags based attribute
whereas 0 is only going to come into play in rare circumstances and it
removes the ability to provide a speciallly named NoFlags value.

Why would it either add complexity (if you don't use it) or remove your
ability to add a 0-valued member? Because if it is a member of a given enum, its plain silly. I would have
other issues with a special keyword.


Saying "it's silly" doesn't asnwer the question.

Two enum mebers that mean the same thing, one of which makes sense in the
context of the enum and the other is there because someone thinks that
implicit cast from zero is *a bad idea*. That is the definition of silly,
IMHO.

It removes it at the cost of a new keyword(which users need to know). As
it stands there is only about three keywords that are very rarely used,
yet each has some value. Two of which, unsafe and fixed, make sense. The
third, stackalloc, could probably have been written as an API function or
a function of new, each other keyword has a practical common usage.
I don't think drawing a line between null pointers and unintialized enums
is a particularly valid point, either.


Both are using "0" to mean something other than the integer 0. A bad
idea.


Except that an enum is an integer, except it has cute names for some
members. Every enum *is* based off an integer(or byte, technically, which is
an integer for the purposes of this discussion). Not understanding that an
enum is infact an integer with some named values is going to cause huge
amounts of issue with people. The implicit 0 conversion isn't the least of
them, but it is certainly consistent with every other issue you'll run into.

That said, I would have probably not complained if the designers had chosen
to require explicit casting of the 0 constant into an enum, but I personally
think you can deal with that quirk.

The compiler warning could probably be better, and more to the point the
compiler should issue an explicit warning when there is both an enum and an
integer overload(with casts to distinguish and stop the warning), however I
don't think it requires a change to the language.
Nov 16 '05 #16
The point still is that 0 is normally an integer constant and this special
rule causes it to have a special meaning. To users, this is confusing
because:
- one integer constant (0) does not behave like another integer constant
(say 1)
- an integer variable with value 0 does not behave like the integer
constant.

Perhaps the rule 6.1.3 should only apply to enums marked as bitwise (flags)?

More interesting is why does one explicit cast, (double)0.0, disables the
implicit int promotion but another explicit cast, (int)0, does not disable
the implicit enum promotion?

Also, from the MSDN I pulled "The same value can be assigned to multiple
fields. When this occurs, you must mark one of the values as the primary
enumeration value for purposes of reflection and string conversion." So how
does one mark a value as the primary enumeration value in C#?

Philippe
Nov 16 '05 #17

"Philippe Bertrand" <my*****@ianywhere.com> wrote in message
news:10*************@corp.supernews.com...
The point still is that 0 is normally an integer constant and this special
rule causes it to have a special meaning. To users, this is confusing
because:
- one integer constant (0) does not behave like another integer constant
(say 1) In most cases, atleast. In virtually all other situations this isn't an
issue.
- an integer variable with value 0 does not behave like the integer
constant.
It shouldn't, they are two different things. You also can't pass the
constant 0 by ref.

Perhaps the rule 6.1.3 should only apply to enums marked as bitwise
(flags)?

More interesting is why does one explicit cast, (double)0.0, disables the
implicit int promotion but another explicit cast, (int)0, does not disable
the implicit enum promotion?
Because (double)0.0 results in a double constant, (int)0 is still an int(I
think the compiler removes superflous casts like this).
Also, from the MSDN I pulled "The same value can be assigned to multiple
fields. When this occurs, you must mark one of the values as the primary
enumeration value for purposes of reflection and string conversion." So
how
does one mark a value as the primary enumeration value in C#?
On that I have *no* idea. I think the enum structure simply uses the first
defined, but I could be wrong on that.

That is something to look into...
Philippe

Nov 16 '05 #18

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:ub**************@tk2msftngp13.phx.gbl...
More interesting is why does one explicit cast, (double)0.0, disables the implicit int promotion but another explicit cast, (int)0, does not disable the implicit enum promotion?

Because (double)0.0 results in a double constant, (int)0 is still an int(I
think the compiler removes superflous casts like this).


0.0 is a double both before and after the cast. The fact that they act
differently is, to me, the strangest part.

Mike
Nov 16 '05 #19

"Philippe Bertrand" <my*****@ianywhere.com> wrote in message
news:10*************@corp.supernews.com...
The point still is that 0 is normally an integer constant and this special
rule causes it to have a special meaning. To users, this is confusing
because:
- one integer constant (0) does not behave like another integer constant
(say 1)
- an integer variable with value 0 does not behave like the integer
constant.


Precisely like null pointers in C:

(int *)0 yields a null pointer
int x = 0; (int *)x does not.

And a bad idea, for the same reason.
Nov 16 '05 #20

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:OK*************@TK2MSFTNGP12.phx.gbl...

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:ub**************@tk2msftngp13.phx.gbl...
> More interesting is why does one explicit cast, (double)0.0, disables the > implicit int promotion but another explicit cast, (int)0, does not disable > the implicit enum promotion?
> Because (double)0.0 results in a double constant, (int)0 is still an
int(I
think the compiler removes superflous casts like this).


0.0 is a double both before and after the cast. The fact that they act
differently is, to me, the strangest part.


It is odd, but the compiler probably converts 0.0 to the literal 0. It may
not be spec'd as such(I havn't checked teh fine print), but it is an
understandable issue consider 0.0 and 0 are effectivly the same thing.

However, by issuing a cast you probably get something like
CastExpression(double,LiteralExpression(0)) in the parse tree, instead of
LiteralExpression(0).

As to why (int) wouldn't do the same thing is beyond me, perhaps (int) casts
are discarded on literals. Mike

Nov 16 '05 #21

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:Ob**************@TK2MSFTNGP11.phx.gbl...

"Mike Schilling" <ms*************@hotmail.com> wrote in message
news:OK*************@TK2MSFTNGP12.phx.gbl...

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:ub**************@tk2msftngp13.phx.gbl...
> More interesting is why does one explicit cast, (double)0.0, disables the
> implicit int promotion but another explicit cast, (int)0, does not

disable
> the implicit enum promotion?
>
Because (double)0.0 results in a double constant, (int)0 is still an
int(I
think the compiler removes superflous casts like this).


0.0 is a double both before and after the cast. The fact that they act
differently is, to me, the strangest part.


It is odd, but the compiler probably converts 0.0 to the literal 0. It may
not be spec'd as such(I havn't checked teh fine print), but it is an
understandable issue consider 0.0 and 0 are effectivly the same thing.


They're not the same in any other context I know of, though: they're of
different types. For example:

int i = 0.0;

leads to the error

error CS0029: Cannot implicitly convert type 'double' to 'int'

Entirely correct, since such a cast can lose information, even though it
doesn't for this value.


However, by issuing a cast you probably get something like
CastExpression(double,LiteralExpression(0)) in the parse tree, instead of
LiteralExpression(0).

As to why (int) wouldn't do the same thing is beyond me, perhaps (int) casts are discarded on literals.


I think we agree here that the obsreved behavior seems to fall out of the
compiler implemenation, rather than being derivable from the language
definition..
Nov 16 '05 #22
>>
It is odd, but the compiler probably converts 0.0 to the literal 0. It
may
not be spec'd as such(I havn't checked teh fine print), but it is an
understandable issue consider 0.0 and 0 are effectivly the same thing.
They're not the same in any other context I know of, though: they're of
different types. For example:

int i = 0.0;

leads to the error

error CS0029: Cannot implicitly convert type 'double' to 'int'

Entirely correct, since such a cast can lose information, even though it
doesn't for this value.


I agree, however I do suspect that 0 is defined the same or similarly. My
guess would be that the Enum cast doesn't check type, instead it simply
looks for a literal valued to 0. Whats more intresting, does something like
0.0f or 0l result in the enum overload being called?

However, by issuing a cast you probably get something like
CastExpression(double,LiteralExpression(0)) in the parse tree, instead of
LiteralExpression(0).

As to why (int) wouldn't do the same thing is beyond me, perhaps (int)

casts
are discarded on literals.


I think we agree here that the obsreved behavior seems to fall out of the
compiler implemenation, rather than being derivable from the language
definition..


Yes, I don't *think* there is anything in the spec that defines 0.0 as
implicitly convertible to an enum, however I havn't sat down and traced the
spec entirely, so I can't state that the spec doesn't define this.

However, in the spec or not, it is now effectivly a semantically required
portion of the language. Microsoft can't really change its compiler and
third party compiler vendors would have to support this in either case,
removing it will break code, unfortunatly.
Nov 16 '05 #23
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:eZ**************@TK2MSFTNGP10.phx.gbl...

It is odd, but the compiler probably converts 0.0 to the literal 0. It
may
not be spec'd as such(I havn't checked teh fine print), but it is an
understandable issue consider 0.0 and 0 are effectivly the same thing.
They're not the same in any other context I know of, though: they're of
different types. For example:

int i = 0.0;

leads to the error

error CS0029: Cannot implicitly convert type 'double' to 'int'

Entirely correct, since such a cast can lose information, even though it
doesn't for this value.


I agree, however I do suspect that 0 is defined the same or similarly. My
guess would be that the Enum cast doesn't check type, instead it simply
looks for a literal valued to 0. Whats more intresting, does something
like 0.0f or 0l result in the enum overload being called?


Good question. What the C# spec says is:

13.1.3 Implicit enumeration conversions
An implicit enumeration conversion permits the decimal-integer-literal 0
to be converted to any enum-type.

According to 9.4.4.2, the decimal-integer-literal 0 can be

0, possibly suffixed by one of U u L l UL Ul uL ul LU Lu lU lu
0x0, possilby suffixed the same way

or of course 00, 0x00, 000, 0x000, etc, again possibly suffixed. And I
think this is exactly what was intended. It's not that any integer values
are implicitly converted to enums. It's that there is a special constant
that's a member of all enum types, it means "no flags set", and it's
spelled "0".

As far as I can see, that's the only place the implicit conversion should
apply, so, in theory, 0l yes, 0f no.
I think we agree here that the observed behavior seems to fall out of the
compiler implementation, rather than being derivable from the language
definition..


Yes, I don't *think* there is anything in the spec that defines 0.0 as
implicitly convertible to an enum, however I havn't sat down and traced
the spec entirely, so I can't state that the spec doesn't define this.


I did some searching for "conversion", "cast:", etc. and didn't find
anything suggestive-looking.

However, in the spec or not, it is now effectivly a semantically required
portion of the language. Microsoft can't really change its compiler and
third party compiler vendors would have to support this in either case,
removing it will break code, unfortunatly.


There are ways to address this, e.g:

Version N+1 of the compiler issues a warning that the usage is
deprecated and will cause an error in future releases
Version N+2 issues an error unless a special compatibility-mode flag is
set
Version N+3 issues an error, period

But this is a small enough point that, I agree, there's no real point in
making the compiler stricter.
Nov 16 '05 #24

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:ub**************@tk2msftngp13.phx.gbl...

"Philippe Bertrand" <my*****@ianywhere.com> wrote in message
news:10*************@corp.supernews.com...
Also, from the MSDN I pulled "The same value can be assigned to multiple
fields. When this occurs, you must mark one of the values as the primary
enumeration value for purposes of reflection and string conversion." So
how
does one mark a value as the primary enumeration value in C#?


On that I have *no* idea. I think the enum structure simply uses the first
defined, but I could be wrong on that.

I get a different order if I'm making an assembly for the Compact Framework
than if I'm making it for the regular framework.

I also noticed that out of 4 pairs of enumerations with same numeric value,
in the .NET Framework only in 3 pairs, the ToString() output is the first
one defined!

Philippe
Nov 16 '05 #25
> There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".

Consider this:

if ((val & SomeEnum.Foo) == 0) {
}

W/out this rule, the bool expression has to
be written like:

if ((val & SomeEnum.Foo) == (SomeEnum)0) {
}

Why not a keyword "empty" which can implicitly cast to every enum type or
maybe also to every value type since every value type ahs a well defined
state in which every bit is zeroed out (which is what the default ctor of
every struct does)

os following could be possible:

MyStruct s = empty;
Point p = empty;
int i = empty;

if ((val & SomeEnum.Foo) == empty) {}

maybe it could also used in generics instread of T.default.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #26

"cody" <pl*************************@gmx.de> wrote in message
news:uv**************@TK2MSFTNGP12.phx.gbl...
There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".

Consider this:

if ((val & SomeEnum.Foo) == 0) {
}

W/out this rule, the bool expression has to
be written like:

if ((val & SomeEnum.Foo) == (SomeEnum)0) {
}

Why not a keyword "empty" which can implicitly cast to every enum type or
maybe also to every value type since every value type ahs a well defined
state in which every bit is zeroed out (which is what the default ctor of
every struct does)

os following could be possible:

MyStruct s = empty;
Point p = empty;
int i = empty;

if ((val & SomeEnum.Foo) == empty) {}

maybe it could also used in generics instread of T.default.


Well, default is already set(default(T) now), and may be a better solution
for an Enum at this point(I havn't tested to see if it works, but it is much
nicer than implicit 0 conversion).
Also, I think it would be better to simply have:
MyStruct s = default;
rather than defining a new keyword.
Nov 16 '05 #27
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> schrieb im
Newsbeitrag news:%2****************@tk2msftngp13.phx.gbl...

"cody" <pl*************************@gmx.de> wrote in message
news:uv**************@TK2MSFTNGP12.phx.gbl...
There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".

Consider this:

if ((val & SomeEnum.Foo) == 0) {
}

W/out this rule, the bool expression has to
be written like:

if ((val & SomeEnum.Foo) == (SomeEnum)0) {
}

Why not a keyword "empty" which can implicitly cast to every enum type or maybe also to every value type since every value type ahs a well defined
state in which every bit is zeroed out (which is what the default ctor of every struct does)

os following could be possible:

MyStruct s = empty;
Point p = empty;
int i = empty;

if ((val & SomeEnum.Foo) == empty) {}

maybe it could also used in generics instread of T.default.


Well, default is already set(default(T) now), and may be a better solution
for an Enum at this point(I havn't tested to see if it works, but it is

much nicer than implicit 0 conversion).
Also, I think it would be better to simply have:
MyStruct s = default;
rather than defining a new keyword.


It looks very strange but it would do the job :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #28
hi cody,
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> schrieb im
Newsbeitrag news:%2****************@tk2msftngp13.phx.gbl...
"cody" <pl*************************@gmx.de> wrote in message
news:uv**************@TK2MSFTNGP12.phx.gbl...
There is no magic. The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".

Consider this:

if ((val & SomeEnum.Foo) == 0) {
}

W/out this rule, the bool expression has to
be written like:

if ((val & SomeEnum.Foo) == (SomeEnum)0) {
}
Why not a keyword "empty" which can implicitly cast to every enum type
or
maybe also to every value type since every value type ahs a well defined
state in which every bit is zeroed out (which is what the default ctor
of
every struct does)

os following could be possible:

MyStruct s = empty;
Point p = empty;
int i = empty;

if ((val & SomeEnum.Foo) == empty) {}

maybe it could also used in generics instread of T.default.


Well, default is already set(default(T) now), and may be a better solution
for an Enum at this point(I havn't tested to see if it works, but it is


much
nicer than implicit 0 conversion).
Also, I think it would be better to simply have:
MyStruct s = default;
rather than defining a new keyword.

It looks very strange but it would do the job :)


I'd vote for "empty" ;-)

Consider this not quite uncommon enum usage pattern:

switch (someEnumVarWithBrandNewDefaultSemantics)
{
case TotallyWeird:
return foo;

case default:
return bar;

default:
return idonttakeit;
}

That's ugly. Languages have to be nice, consistent and orthogonal.
I fully understand why Anders went for "0" ;-)

bye
Rob
Nov 16 '05 #29

"Robert Jordan" <ro*****@gmx.net> wrote in message
news:ch*************@news.t-online.com...
hi cody,
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> schrieb im
Newsbeitrag news:%2****************@tk2msftngp13.phx.gbl...
"cody" <pl*************************@gmx.de> wrote in message
news:uv**************@TK2MSFTNGP12.phx.gbl...

>There is no magic. The language designers wanted to avoid
>constructs like "(SomeEnum)0", because enums may be
>[Flags]-able, and thus they may be "0" w/out having
>a literal with the value "0".
>
>Consider this:
>
>if ((val & SomeEnum.Foo) == 0) {
>}
>
>W/out this rule, the bool expression has to
>be written like:
>
>if ((val & SomeEnum.Foo) == (SomeEnum)0) {
>}
Why not a keyword "empty" which can implicitly cast to every enum type


or
maybe also to every value type since every value type ahs a well defined
state in which every bit is zeroed out (which is what the default ctor


of
every struct does)

os following could be possible:

MyStruct s = empty;
Point p = empty;
int i = empty;

if ((val & SomeEnum.Foo) == empty) {}

maybe it could also used in generics instread of T.default.
Well, default is already set(default(T) now), and may be a better
solution
for an Enum at this point(I havn't tested to see if it works, but it is


much
nicer than implicit 0 conversion).
Also, I think it would be better to simply have:
MyStruct s = default;
rather than defining a new keyword.

It looks very strange but it would do the job :)


I'd vote for "empty" ;-)


I wouldn't. New keyword is bad mojo, especially for something as minor as
this. I am happy with 0 myself, ;).
Nov 16 '05 #30
> >>>>There is no magic. The language designers wanted to avoid
>constructs like "(SomeEnum)0", because enums may be
>[Flags]-able, and thus they may be "0" w/out having
>a literal with the value "0".
>
>Consider this:
>
>if ((val & SomeEnum.Foo) == 0) {
>}
>
>W/out this rule, the bool expression has to
>be written like:
>
>if ((val & SomeEnum.Foo) == (SomeEnum)0) {
>}
Why not a keyword "empty" which can implicitly cast to every enum type


or
maybe also to every value type since every value type ahs a well definedstate in which every bit is zeroed out (which is what the default ctor


of
every struct does)

os following could be possible:

MyStruct s = empty;
Point p = empty;
int i = empty;

if ((val & SomeEnum.Foo) == empty) {}

maybe it could also used in generics instread of T.default.
Well, default is already set(default(T) now), and may be a better solutionfor an Enum at this point(I havn't tested to see if it works, but it is


much
nicer than implicit 0 conversion).
Also, I think it would be better to simply have:
MyStruct s = default;
rather than defining a new keyword.

It looks very strange but it would do the job :)


I'd vote for "empty" ;-)

Consider this not quite uncommon enum usage pattern:

switch (someEnumVarWithBrandNewDefaultSemantics)
{
case TotallyWeird:
return foo;

case default:
return bar;

default:
return idonttakeit;
}

This is indeed very dangerous, it would lead to subtly bug. I sometimes
inadvertantly write case default: instead of default: which would compile
fine but doing some different things.
So I'd also vote for "empty" again :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #31

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Ryan Mitchley | last post by:
Hi all I have code for an object factory, heavily based on an article by Jim Hyslop (although I've made minor modifications). The factory was working fine using g++, but since switching to the...
4
by: August1 | last post by:
I've written an interface and implementation file along with a client source file that allows the use of an overloaded subtraction operator. However, when using the program, I'm running into a...
2
by: Tony Johansson | last post by:
Hello Experts!! I have two small classes called Intvektor and Matris shown at the bottom and a main. Class Intvektor will create a one dimension array of integer by allocate memory dynamically...
10
by: john bailo | last post by:
Can a web method be overloaded? To support varying numbers of input parameters?
19
by: Martin Oddman | last post by:
Hi, I have a compiling problem. Please take a look at the code below. I have an application that is built upon three tiers: one data tier (Foo.DataManager), one business tier (Foo.Kernel) and...
3
by: hazz | last post by:
The following classes follow from the base class ' A ' down to the derived class ' D ' at the bottom of the inheritance chain. I am calling the class at the bottom, "public class D" from a client...
18
by: John Rusk | last post by:
Hi, I have some weird compiler behaviour, so I'm hoping that one of the gurus here will be able to tell me whether or not it really is a compiler bug. In short, the compiler is saying that it...
0
by: erik.erikson | last post by:
I am getting a compiler error that I can't well explain or even understand the origin of (though I boiled it down close...). Below is a bare-bones example. What I am doing is defining the...
1
by: dileepd | last post by:
Hi Every one, Could you please let me know if you have any clue about following things. 1. Whether type bool acts like a kind of signed int type in g++ on solaris 9(a/c to my invetsigation it...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.