Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion: consider target-type when the compiler can't determine the type of a ternary #877

Closed
alrz opened this issue Sep 2, 2017 · 12 comments

Comments

@alrz
Copy link
Member

alrz commented Sep 2, 2017

Currently, C# requires either of operands in a ternary to be convertible to one another, e.g.

void M(C2 a, C3 b, bool c)
{
  C1 x = c ? a : b; // ERROR
  C1 y = c ? b : a; // ERROR
}
class C1 {}
class C2 : C1 {}
class C3 : C1 {}

But in the above example the compiler could consider the target-type C1 for the conditional expression instead of requiring a cast on either of operands.

Note that the proposal #33 has been limited to nullables so that's not an alternative here.

Other constructs that can be target-typed:

  • ?? operator: SyntaxNode x = expression ?? statement;.
  • switch expressions: Size size = e switch { p1 => new(1, 2), p2 => new(3, 4) };
@vladd
Copy link

vladd commented Sep 3, 2017

This way, the behaviour will be inconsistent, as the target type is available for assignment LHS but not for arbitrary expressions.

C1 x = c ? a : b;
string s = x.ToString();

would work whereas

string s = (c ? a : b).ToString();

would not.

@DavidArno
Copy link

@vladd,
Whereas:

string s = ((c ? a : b) as C1).ToString();

would work. That would overcome any inconsistency.

@alrz
Copy link
Member Author

alrz commented Sep 4, 2017

@DavidArno Note: as doesn't do target typing, it tries to "convert" the expression to that type. e.g (null, null) as (C, C)? is an error whereas a direct cast works. null/default is a special case though.

@alrz
Copy link
Member Author

alrz commented Sep 4, 2017

@vladd The ternary in (c ? a : b).ToString(); does not have a type or target-type, so you should either cast it to C1 or have it to produce a "most specific type" which is what intersection types are about and they are relatively costly in implementation as they require clr changes.

@DavidArno
Copy link

@alrz, nor does = do target typing. So maybe I should have said that by using as, it could do the same type inference as you propose in the OP.

@vladd
Copy link

vladd commented Sep 6, 2017

@alrz If I understand correctly, in C# pretty much every expression (with exception of method groups/lambdas and null literal) has its intrinsic type. This allows for the logic "for any expression, we can get the types of its constituent parts, and deduce the type of the expression itself".

The way you are proposing breaks this logic, as the conditional expression would need to know the outer type in order to infer the inner types. This raises the question: where should be the border between top-to-bottom and bottom-to-top type inference?

@alrz
Copy link
Member Author

alrz commented Sep 6, 2017

Target-typing is a well-defined concept in the language. ternary itself does apply it to either of operands that does not have a type, e.g. c ? obj : default. I'm just suggesting we apply it to both operands if they are not implicitly convertible to each other.

@vladd
Copy link

vladd commented Sep 6, 2017

@alrz I see your point. Till now typeless (or top-to-bottom-typed) expressions were either simple expressions like null or default, or lambdas. Now, either of the alternatives in the conditional expression can be another conditional expression, so this means that type inference must be propagated down the tree, right? So this is more like lambda case, not like null case.

@alrz
Copy link
Member Author

alrz commented Sep 21, 2017

Another use case from dotnet/corefxlab#1742 (comment)

EDIT: that example just works with dotnet/roslyn#22162 in place. so not related here.

@HaloFour
Copy link
Contributor

@alrz

Does that imply that the language team is also relaxing the restrictions on the use of stackalloc? Currently it can't be used in expressions at all.

@alrz
Copy link
Member Author

alrz commented Sep 21, 2017

@HaloFour Relevant PR: dotnet/roslyn#22162, being used over here: dotnet/corefxlab#1742

@alrz
Copy link
Member Author

alrz commented Jan 7, 2020

Closing in favor of championed issue #2460

@alrz alrz closed this as completed Jan 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants