Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ternary Expression with Interfaces as a Base Class

I am attempting to create a ternary expression and I am getting the following error

"Type of conditional expression cannot be determined because there is no implicit conversion between LiveSubscription and DisconnectedSubscription"

The same logic works in an if statement, but I wanted to understand why it won't work in a ternary expression -

Here is the gist of what I am trying to do:

public interface IClientSubscription
{
    bool TryDisconnect();
}

public class LiveSubscription : IClientSubscription
{
    public bool TryDisconnect()
    {
        return true;
    }
}

public class DisconnectedSubscription : IClientSubscription
{
    public bool TryDisconnect()
    {
        return true;
    }
}

public class ConnectionManager
{
    public readonly IClientSubscription Subscription;

    public ConnectionManager(bool IsLive)
    {
        // This throws the exception
        Subscription = (IsLive)
            ? new LiveSubscription()
            : new DisconnectedSubscription();

        // This works
        if (IsLive)
        {
            Subscription = new LiveSubscription();
        }
        else
        {
            Subscription = new DisconnectedSubscription();
        }
    }
}

I could always switch it to an if/else but I wanted to understand what is going wrong first!

like image 766
William Avatar asked Mar 21 '12 18:03

William


People also ask

Is it good practice to use ternary operator in Java?

Overall, you should only use ternary statements when the resulting statement is short. Otherwise, write a normal if statement. The purpose of a ternary operator is to make your code more concise and readable. Moving a complex if statement into a ternary operator goes against that goal.

How do you use ternary operator for 3 conditions?

The conditional (ternary) operator is the only JavaScript operator that takes three operands: a condition followed by a question mark ( ? ), then an expression to execute if the condition is truthy followed by a colon ( : ), and finally the expression to execute if the condition is falsy.

What is ternary operator with example?

A ternary operator lets you assign one value to the variable if the condition is true, and another value if the condition is false. The if else block example from above could now be written as shown in the example below. var num = 4, msg = ""; msg = (num === 4) ?

Can we use return statement in ternary operator?

Explanation: In a ternary operator, we cannot use the return statement.


1 Answers

You need to cast at least one of the operands to IClientSubscription:

Subscription = (IsLive)
            ? (IClientSubscription)new LiveSubscription()
            : new DisconnectedSubscription();

The reason is that the ternary expression is of a certain type which is determined by the operands. Basically, it tries to cast the second operand to the type of the first or vice versa. Both fail here, because LiveSubscription isn't an DisconnectedSubscription and vice versa.
The compiler doesn't check whether both share a common base type.


Trying to answer your question in the comment:

No, ternary expressions are not some sort of object, but a ternary expression is the right hand part of an assignment. Each right hand part expression of an assignment has a certain type, otherwise it would be impossible to assign this expression to the variable on the left hand side.
Examples:

  • var x = Guid.NewGuid()

    The right hand side expression (Guid.NewGuid()) is of type Guid, because the method NewGuid() returns a Guid.

  • var x = y.SomeMethod()

    The right hand side expression is of the type of the return type of SomeMethod().

  • var x = IsLive ? "a" : 1

    This is obviously invalid, isn't it? What type should x be? A string or an int?
    This would lead to the exact same error message that you had with your code.

  • Your example a bit changed:

    var subscription = (IsLive) ? new LiveSubscription()
                                : new DisconnectedSubscription();
    

    Note the var before subscription, we now initialize a new variable, not an existing. I think even here, it is obvious what the problem is: What type should subscription be? LiveSubscription or DisconnectedSubscription? It can be neither, because depending on IsLive it needs to be either the one or the other.

About the comparison with if:

In your code where you assign a new LiveSubscription instance or a new DisconnectedSubscription instance to Subscription an implicit cast to IClientSubscription is occurring, because the compiler knows that Subscription is of type IClientSubscription and both LiveSubscription and DisconnectedSubscription can implicitly be converted to that interface.
The assignment with the ternary expression is a bit different, because the compiler first tries to evaluate the ternary expression and only afterwards it tries to assign it to Subscription. This means that the compiler doesn't know that the result of the ternary expression needs to be of type IClientSubscription.

like image 89
Daniel Hilgarth Avatar answered Oct 21 '22 09:10

Daniel Hilgarth