tags:

views:

129

answers:

8

It seems the compiler is not going let this syntax fly.

void main()
{
  foo(false?0:"");
}

void foo(int i) {return;}
void foo(string s) {return;}

The only other way I can see of fixing this is something as follows:

void bar(object o) 
{
 if (o is string){//do this}
 else{//im an int, do this}
}

Anyone have any better ideas?

+1  A: 

You're example doesn't make a whole lot of sense (the second example doesn't relate to the first).

I think the first example would be fine as:

void main()
{
    foo("");
}

Since 0 will never be passed anyway (false is always false) and you can't use the inline conditional operator without an assignment somewhere (which your example is lacking).

As for the second way, that is probably how I would prefer to see it:

void bar(object o)
{
    if(o is string) foo(o as string);
    else foo((int)o);
}
Justin Niessner
And why wouldn't you simply overload Bar for string and int?
Rune FS
@Rune FS - Foo is overloaded, but since o is of type Object the proper overload can't be determined without casting o to a more specific type. The logic tests for the appropriate cast.
Justin Niessner
@Justin: Am I going crazy? Everybody seems to be suggesting something like that last suggestion of yours, but I am sure it is illegal! `foo` returns nothing, so it can't be used like that in a ternary expression -- am I wrong?
Dan Tao
@Dan Tao - No, that's why I got rid of it. I had to double check myself!
Justin Niessner
@Justin: Ha, ok, I guess you had probably already fixed it by the time my comment showed up. Good to know I'm not losing my mind, anyway.
Dan Tao
@Justin but if you overloaded bar for string and int that wouldn't be needed. The only reason is that Bar takes and object. So why not fix that :)
Rune FS
+1  A: 

I wouldn't pass in an object as a parameter. The int will be boxed, which is a little less efficient. Let the compiler figure out which method to call.

If you wrote:

foo(0);
foo("");

The appropriate method would be called. You could also write:

if (condition) {
  foo(0);
} else {
  foo("");
}

Depending on what you're trying to do (your example is lacking in a little detail).

Bob
+2  A: 

The method call of foo is determined at compile time, so it cannot call a different method (or overload) based on the result of evaluating the condition. Instead, try something like this:

condition ? foo(0) : foo("")

This way, the compiler will succeed in performing overload resolution and will resolve the first call to foo(int) and the second call to foo(string).

EDIT: As noted by other, you cannot use the ?: operator as a statement, nor can you use methods which return void in it. If your actual methods return compatible types, you could do something like:

int result = condition ? foo(0) : foo("");

If not, you must use an if:

if (condition)
    foo(0);
else
    foo("");
Allon Guralnek
Well, but you cannot use a ternary expression by itself on a line in C#... so this is kind of misleading.
Dan Tao
-1 You can't use a conditional expression by itself without an assignment.
Justin Niessner
If this would work it would be great, but i'd have to do something like : var x = condition ? foo(0) : foo(""); and make foo() return something.
maxp
@Dan, @Justin: True. A statement also ends in a semicolon. My above code sample is not a statement, but an expression. In the OP's case, it doesn't even make sense to use a condition, since he's branching on a `false` constant, so I decided to explain the problem (overload resolution) slightly outside of the context of the question. He can then take the understanding of overload resolution and apply to his specific problem, which I doubt is actually what he presented above. His actual methods might return something, or he might be doing something different altogether.
Allon Guralnek
@Allon: I get what you're saying, but the problem isn't *just* that the expression isn't used in an assignment. It's also that, in the OP's code, `foo` doesn't return anything; so that expression you've suggested would *never* work, not with a semi-colon, not in any context. I think it would be good to emphasize that in your answer -- for some *other* two `foo` overloads with a consistent return type, that would be a viable alternative; in the OP's case, it's just not an option.
Dan Tao
@Dan: You're right again, and I did just that right after I wrote that comment. You notice that I changed `false` to `condition`. My mistake was not changing the rest, to make it clear that I wasn't using _his_ foo.
Allon Guralnek
@maxp: The `?:` operator is meant to be embedded in an expression, not used on its own. That's what the `if` keyword is for.
Allon Guralnek
A: 

This:

foo(false?0:"")

Could be this:

false ? foo(0) : foo("")
mmsmatt
-1 You have the same mistake as Allon Guralnek. You can't use the conditional operator without some kind of assignment. This won't compile on its own.
Justin Niessner
I take it as an expression, in which case it's quite valid, so long as `foo` isn't `void`.
Steven Sudit
+3  A: 

You cannot use a method with a void return type in a ternary expression in this way. End of story.

To understand why this is, remember what the ternary operator actually does -- it evaluates to the following:

(condition ? [true value] : [false value])

What this implies is that the following code:

int x = a ? b : c;

Must be rewritable to:

int x;
if (a)
{
    x = b;
}
else
{
    x = c;
}

The two above are logically identical.

So how would this work with a method with void as its return type?

// Does this make sense?
int x = condition ? foo(s) : foo(i);

// Or this?
if (condition)
{
    x = foo(s);
}
else
{
    x = foo(i);
}

Clearly, the above is not legal.

That said, others' suggestions would otherwise be valid if only your foo overloads returned a value.

In other words, if your signatures looked like this:

object foo(string s);
object foo(int i);

Then you could do this (you're throwing away the return value, but at least it'll compile):

object o = condition ? foo(0) : foo("");

Anyway, the ol' if/else is your best bet, in this case.

Dan Tao
A: 

Both results of the conditional operator must of the same type (or be implicitly convertible). So foo(false ? 0 : "") won't work because it is trying to return an Int32 and a String. Here's more information on the conditional operator.

The fix I would do is change that line to false ? foo(0) : foo("").

EDIT: Derp, can't use a conditional operator just in the open like that. They can only be used for assignments. You'll have to use a if/else block. Not in one line, but it'll do in a pinch.

comradecow
This fix has been suggested a few times on this thread already, but must return something, so as it is, would not compile :)
maxp
Remembered that right after I clicked the shiny 'post' button :D
comradecow
+1  A: 

The conditional operator needs the true and false part to be of the same type. Which is why it's not compiling.

var x = condition ? 0 : "";

What type should the compiler choose for x? If you really want it to choose object make a cast or you could force it to choose dynamic in which case method overload would still work but you loose type safety. Both are however strong smells. Having to test the runtime type is usually a design error but with the limited code (that will always have the same result) it's hard to help with a different approach that would require testing on runtime types

Rune FS
+1  A: 

If you use Inline if expressions in C#, both parts before and after the ":" have to be of the same type. What you are intending would never work.

Even if you like to do something like this:

 DateTime? theTime = true ? DateTime.Now : null;

The compiler is not satisfied. In this case you will have to use:

DateTime? theTime = true ? DateTime.Now : default(DateTime?);
JanW