ternary operator and casting

B

Bob Hoeppner

In the following code

//add to bool or double Dictionary
this.m_unit.Add((unittype == "b")? unitnum:(double)unitnum);

The bool dictionary uses an integer index, the double uses a double
index, which some may take issue with, but that's a different
discussion. The problem is that unitnum is always cast to a double, even
when unittype is "b". That seems like a bug to me.

If I change it to

this.m_unit.Add((unittype == "d")? (double)unitnum:unitnum);

it still always casts it to a double. I'm annoyed that the ternary
operator always casts unitnum to a double.

(parenthetical discussion)

The object is to later be able to set values, like so

//1234 is a bool
Grp.Unit[1234] = true;
//4321 is a double
Grp.Unit[4321d] = 1.0;
//there is also a uint index for conversion between bool and double
//set bool from double
Grp.Unit[1234u] = 1.0;
//set double from bool
double myvalue = Grp.Unit[1234u];

but, like I said, that's not the discussion I want to have. There is a
lot of code, and it minimizes it, especially when dealing with
bool-to-double conversions.
 
J

Jon Skeet [C# MVP]

In the following code

//add to bool or double Dictionary
this.m_unit.Add((unittype == "b")? unitnum:(double)unitnum);

The bool dictionary uses an integer index, the double uses a double
index, which some may take issue with, but that's a different
discussion. The problem is that unitnum is always cast to a double, even
when unittype is "b". That seems like a bug to me.

No - it's a flaw in your understanding of the conditional operator.

The conditional operator is (as you know) an expression of the form
a ? b : c. That expression is of a single type, in the end. Both the
subexpressions "b" and "c" have to be convertible to the overall type
of the expression, which (IIRC) is always either the type of b or the
type of c.

In your case, you end up with b and c being unitnum (type=int) and
(double)unitnum (type=double). int is implicitly convertible to
double, but not vice versa - so the overall type of the expression is
double. That means you always get the Add(double) overload being
called, and there is indeed always a conversion.

Assuming the Add method is overloaded (once for int and once for
double) then you need to have two different method calls to get it to
work. Any one method call will only resolve to a single overload.

Then again, it's quite strange to see an overload like that, so it's
possible that my assumptions about the type of m_unit are incorrect.
If the explanation above hasn't helped you, could you provide a short
but complete program which demonstrates the problem?

Jon
 
B

Bob Hoeppner

Yes, I see my understanding was flawed. It makes sense the one ternary
operator would have to return one datatype. This demonstrates that the
ternary operator is not an exact shorthand equivalent for an if/else
statement. Thanks.
 
M

Michael A. Covington

this.m_unit.Add((unittype == "b")? unitnum:(double)unitnum);
The bool dictionary uses an integer index, the double uses a double
index, which some may take issue with, but that's a different
discussion. The problem is that unitnum is always cast to a double, even
when unittype is "b". That seems like a bug to me.

I just looked in the C# Annotated Standard...

The semantics of the ternary operator requires the type of the expression to
be determined at compiled time. So (condensing several rules into one
sentence) it is whatever is compatible with both of the expressions after
the ? .
 
B

Bob Hoeppner

I've entered into that discussion on this thread

http://www.developersdex.com/csharp/message.asp?p=1111&r=6224121


Suffice it to say that the overloading of the indexers allows some more
concise code by people programming to the class, which is how those
coding to it prefer. We went over the various ways it could be
implemented. Some lines can get quite long. Here's a shorter one:

Grp.Unit[2770] = FUN(Grp.Unit[772] && !Grp.Unit[2771], ref
Grp.Unit[1800d], Grp.Unit[773d]); // Line 1290

which isn't much of an advantage over, say,

Grp.UnitB[2770] = FUN(Grp.UnitB[772] && !Grp.UnitB[2771], ref
Grp.UnitD[1800], Grp.UnitD[773]); // Line 1290

but when going between booleans and doubles, is, as described in my post
in the other thread.
 

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