Ternary-operator in Interpolated Strings #1409
-
Interpolated strings support fairly involved r-value expressions, but surprisingly not ternary-operator expressions.
results in CS1733. Is this something fairly easy to support? |
Beta Was this translation helpful? Give feedback.
Replies: 21 comments
-
It's not easy to support due to implementation details around how the colon is interpreted. i.e. because i can write: This is a known limitation. The workaround is to simply just surround the expression with parentheses. i.e.
|
Beta Was this translation helpful? Give feedback.
-
It's not easy to support, see the discussion at dotnet/roslyn#12214. In short, the issue is that colon in interpolated string is used as a delimiter for format string. For example Newer versions of the compiler (VS 15.6+) produce a better error message:
As the error message explains, the workaround is to use parentheses: |
Beta Was this translation helpful? Give feedback.
-
Wrap the expression in parenthesis: bool b = ...;
string s = $"This result is {(b ? "true" : "false")}"; |
Beta Was this translation helpful? Give feedback.
-
We also have a fixer to make the change for you: |
Beta Was this translation helpful? Give feedback.
-
Are there cases where this is actually ambiguous? If the compiler produces an error, then it could take a preferred interpretation. |
Beta Was this translation helpful? Give feedback.
-
@bondsbw |
Beta Was this translation helpful? Give feedback.
-
@Joe4evr How is that ambiguous? |
Beta Was this translation helpful? Give feedback.
-
I could probably be convinced that this is a change which is difficult to make in the compiler. However, I don't think I am convinced that there is an ambiguous code that would prevent this from working. I don't believe there is currently any code for which |
Beta Was this translation helpful? Give feedback.
-
I want to recall there being examples posted on CodePlex when the design was being ironed out, but that site has been reduced to an archive which ain't exactly easy to search through. Even if it is possible, what kind of complication would it put on the parser as well as the specification? Is requiring a set of parenthesis really that burdensome? |
Beta Was this translation helpful? Give feedback.
-
No, I was just indicating that I don't believe there is anything that is truly ambiguous (at least not any code I can think of right now). |
Beta Was this translation helpful? Give feedback.
-
We also have |
Beta Was this translation helpful? Give feedback.
-
@gafter would know for certain. However, as i mentioned originally, it's not necessarily about ambiguity. It also heavily plays into "implementation details around how the colon is interpreted". Right now, for better or for worse, the compiler has taken certain approaches around how parsing and lexing works. Those choices led to the position where either:
From my recollection it was an explicit and understood engineering decision to be able to bring about a feature in a timely manner without incurring large costs. Because there is a simple workaround, the team was fine landing there, and hte current situation is one where things are working as designed and intended. |
Beta Was this translation helpful? Give feedback.
-
Right. So now that the feature has shipped, it is probably worth deciding if this should be a long-term backlog item (possibly even "up-for-grabs") to "fix" the compiler to be able to recognize this without the workaround. It is hit fairly often and just seems like "general goodness" to support (but obviously prioritized appropriately, which is fairly low). |
Beta Was this translation helpful? Give feedback.
-
Sure. i think that would be fine, as long as any approach didn't substantially increase complexity or risk in the lexer/parser codebases. In other words, i think it's fine to fix this, if the fix is simple. If not, then the same assessment applies and this was an expected tradeoff of language power versus implementation cost. Note that "cost" here refers not just to the cost to actually make it work, but hte cost in increased complexity and decreased maintainability. If we can keep those costs appropriate then addressing this seems fine. |
Beta Was this translation helpful? Give feedback.
-
In both the specification and the implementation, the source text of the interpolated string is divided up lexically to decide which parts are expressions, which are format strings, and which are literal parts. Then, once the parts are identified, they are parsed. In other words, first we perform lexical analysis of the interpolated string literal to identify its parts, and then we parse those parts. This division of first performing lexical analysis independent of parsing, and then performing parsing on that result, is a classical approach to they way languages are specified and compilers are implemented. All of the suggestions I've heard are to have the parsing affect the lexical structure, and to have the lexical structure affect the parsing. While that might be possible, it is quite a departure from the way the language is currently specified and the way the compiler is currently implemented, and (presuming we could find a way to specify and implement it) I expect it would slow down the compiler. In any case it would be a very large work item for fairly small benefit. |
Beta Was this translation helpful? Give feedback.
-
I'm probably missing something but couldn't we just divide up literal parts and interpolations in lexer and then parse interpolations with a |
Beta Was this translation helpful? Give feedback.
-
@alrz I don't know what |
Beta Was this translation helpful? Give feedback.
-
Neal, the way we did this in JS/TS (approximated to C#'s grammar) was to have the following: InterpolatedString: In this manner we treated interpolated strings totally as normal syntax node, and not at all like a token that was then reinterpreted. The only thing very different here from how we do things today is that the parser has no way to drive the lexer to ask for things like "InterpolatedTextPiece" token. JS/TS solve this by having the parser able to drive the lexer as appropriate for cases like this. In practice it's not problematic (and is necessary given several TS/JS context dependent tokens). However, i agree it would be a departure from how C# currently does things, and it would be complexity we'd have to be very careful about. With this approach though, format specifiers would not be a problem. The ParseInterpolatedSubExpr production would just consume the open curly, then parse out an expression. It would then see if it was followed by a colon, and if so would parse out the optional specifier. |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi The C# language specification and implementation have separate lexical and syntactic grammars. We cannot treat an opening quote (which appears at the end of your production as a stand-along token) as a token by itself, because it is unambiguously the start of a string. As I pointed out before, the approach you suggest would be a significant overhaul of the specification and implementation, and the benefits quite small. |
Beta Was this translation helpful? Give feedback.
-
I'd suggest that it's worth keeping this in mind when discussing possible syntax options for ranges. In the meeting notes most of the examples were written as |
Beta Was this translation helpful? Give feedback.
-
The |
Beta Was this translation helpful? Give feedback.
It's not easy to support due to implementation details around how the colon is interpreted. i.e. because i can write:
$"{x:format_specifiers}"
.This is a known limitation. The workaround is to simply just surround the expression with parentheses. i.e.
var msg = $"{username}: {(isAuthorized ? Approved : Denied)}";