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

String interpolation constants #384

Open
omidkrad opened this Issue Mar 29, 2017 · 32 comments

Comments

Projects
None yet
@omidkrad
Copy link

omidkrad commented Mar 29, 2017

I understand string interpolations are just translated to String.Format calls. But when all arguments are constants, can't we just translate to string concatenation instead?

Example:

This won't compile:

[Obsolete($"Use {nameof(ExecuteAsync)} instead.")]
public void Execute() { }

This compiles OK:

[Obsolete("Use " + nameof(ExecuteAsync) +" instead.")]
public void Execute() { }

This is of course not high priority but could improve the code a bit.

@svick

This comment has been minimized.

Copy link
Contributor

svick commented Mar 29, 2017

Related: #369

@DavidArno

This comment has been minimized.

Copy link

DavidArno commented Mar 30, 2017

@svick, it's not so much related to #369 as a near-identical duplicate! 😀

@jnm2

This comment has been minimized.

Copy link
Contributor

jnm2 commented Mar 30, 2017

I'd prefer not to have to use $$ as #369 requires. If all interpolated strings that become compile-time constants use the invariant culture that would be just fine with me.

@DavidArno

This comment has been minimized.

Copy link

DavidArno commented Mar 30, 2017

@jnm2,

Wouldn't that fall under the dreaded "breaking change" category though as it could change the resultant strings in existing code?

@jnm2

This comment has been minimized.

Copy link
Contributor

jnm2 commented Mar 30, 2017

@DavidArno No, because currently no interpolated strings can be used as compile-time constants, unless I'm wrong? What we have today is compile errors, not working code with a behavior, right?

@DavidArno

This comment has been minimized.

Copy link

DavidArno commented Mar 30, 2017

Oh, OK. So the invariant culture would only apply if it were a constant, which interpolated strings aren't currently compatible with. So there'd be no breaking change. Makes sense and so we could avoid $$, which would be good.

@HaloFour

This comment has been minimized.

Copy link
Contributor

HaloFour commented Mar 30, 2017

It could mean that the following could produce two different values, which I think is not a good thing:

const double x = 123.456;

string x = $"{x}";
const string y = $"{x}";
@jnm2

This comment has been minimized.

Copy link
Contributor

jnm2 commented Mar 30, 2017

I think $$ is way too arbitrary to mean invariant culture. I'd prefer $"test"$i or $i"test" or something a bit more extensible.

@alrz

This comment has been minimized.

Copy link
Contributor

alrz commented Apr 24, 2017

I wonder if we can use string.Concat if and only if:

  1. all interpolations are strings
  2. there is no format specifier

in that case, can we say that such interpolated string can be used in a const context (if all interpolations are also const) without any culture-dependant difference?

@HaloFour

This comment has been minimized.

Copy link
Contributor

HaloFour commented Apr 24, 2017

@alrz

IIRC that would still technically be a breaking change, if only a strictly esoteric one. A custom formatter would still be involved in formatting the raw string value even if there is no specifier. But I agree that the odds of that actually happening approach nil and are likely purely pathological.

@alrz

This comment has been minimized.

Copy link
Contributor

alrz commented Apr 24, 2017

On the other hand, if we only do this in a const context (given those pre-conditions to reduce the chance of producing different strings), it wouldn't be a breaking change at all. Perhaps it's preferable over introducing a new syntax (#369).

@HaloFour

This comment has been minimized.

Copy link
Contributor

HaloFour commented Apr 24, 2017

@alrz

Yes, but again then you'd have identical code possibly producing different results depending on whether it's a const or not.

Anywho, I'd be willing to just make interpolation of strings concatenation in general and live with the possible esoteric breaking changes.

@orthoxerox

This comment has been minimized.

Copy link

orthoxerox commented Apr 24, 2017

I don't mind if I have to write $$. It will be a reminder to the designers of future features and/or languages, like === is in JS and PHP.

@HaloFour

This comment has been minimized.

Copy link
Contributor

HaloFour commented Apr 24, 2017

@orthoxerox

Considering how much the syntax and behavior of string interpolation was argued over on Codeplex I'd say that's kind of unfair. 😉

@alrz

This comment has been minimized.

Copy link
Contributor

alrz commented Apr 24, 2017

@HaloFour

but again then you'd have identical code possibly producing different results depending on whether it's a const or not.

Since string.Concat is culture-dependant, I'm not sure how is that not already the case.

{         
  const string s = "a";
  Console.WriteLine("a" + s); // passes "aa"
}
        
{
  string s = "a";
  Console.WriteLine("a" + s); // calls string.Concat
}
@HaloFour

This comment has been minimized.

Copy link
Contributor

HaloFour commented Apr 24, 2017

@alrz

I'm poking at the IL of String.Concat and I'm not seeing anything that is culture-dependent. All I see is an allocation of a new buffer based on the sizes of the provided strings and copy operations to fill the new buffer.

Yes, the above code produces different IL, but the end result should always be identical short of replacing mscorlib with some kind of hacked version. Programmatically replacing the culture even with a pathological and hypothetical implementation wouldn't affect the outcome.

@alrz

This comment has been minimized.

Copy link
Contributor

alrz commented Apr 24, 2017

@HaloFour

I'm not seeing anything that is culture-dependent.

It calls ToStringon the boxed argument value, just try string.Concat(2.1) with different thread cultures.

@HaloFour

This comment has been minimized.

Copy link
Contributor

HaloFour commented Apr 24, 2017

@alrz

You mentioned concatenation specifically for String. The overload of String.Concat which accepts Strings doesn't call String.ToString().

@alrz

This comment has been minimized.

Copy link
Contributor

alrz commented Apr 24, 2017

@HaloFour It's easy to trick it to call the overload which accepts objects. 😄

const object s = null;
Console.WriteLine("a" + s); // exactly the

object s = null;
Console.WriteLine("a" + s); // same code
@sharwell

This comment has been minimized.

Copy link
Member

sharwell commented Aug 11, 2017

But when all arguments are constants, can't we just translate to string concatenation instead?

There are constants x for which x.ToString() is not a constant. However, if we modify your proposal to require that an interpolated string with no placeholder, or where all placeholders are string constants, be treated as a constant string, then it would work.

@gafter Would you anticipate much push-back from the LDM regarding this proposal?

@jnm2

This comment has been minimized.

Copy link
Contributor

jnm2 commented Aug 11, 2017

I second that. It's probably 99% of the value right there that we're all waiting for.

@gafter

This comment has been minimized.

Copy link
Member

gafter commented Aug 11, 2017

@sharwell I don't imagine this would rise in priority over any of the things we have in mind for the next few releases.

@tannergooding

This comment has been minimized.

Copy link
Member

tannergooding commented Aug 11, 2017

I don't imagine this would rise in priority over any of the things we have in mind for the next few releases.

@gafter, is that with regards to LDM finalizing a design, the compiler team having the people to implement it, or both?

It seems like most language design proposals don't finalize on a design until the compiler team is ready to have someone actively work on or implement it.

However, there are also multiple language proposals where, if the proposal is approved and has a finalized design, there are likely community members who would pick up the work item and help drive the feature in. That is, the compiler team might not be able to implement X until C# 9, but the community might be able to get it implemented for C# 8.

@gafter

This comment has been minimized.

Copy link
Member

gafter commented Aug 11, 2017

@tannergooding This is in regards to the LDM even starting to look at the design instead of working on the design of other things.

@weitzhandler

This comment has been minimized.

Copy link

weitzhandler commented Dec 9, 2017

Any progress on this?

@bchavez

This comment has been minimized.

Copy link

bchavez commented Jan 3, 2018

Would it be possible to enable String Interpolation and String Verbatim by default in C# 8+? If not, maybe could we get an explicit Roslyn opt-in compiler flag that would enable both interpolation and verbatim by default?

98% of the time I'm in need interpolation or verbatim or both. Very often, I'm forgetting to "prefix" my C# strings with $ and @ symbols. I constantly find myself backtracking to the beginning of the string every time I want to enable C# string features.

Imagine, adding something like <SuperString> true </SuperString> in a .csproj that would enable the Roslyn compiler prefix all strings with $@ from the get-go. And writing strings in C# would be so much simpler:

Example:

var name = "Brian";
var theOldWay = $@"Hello, {name}. Your win ratio is 1\2.";
var superString = "Hello, {name}. Your win ratio is 1\2."; //just works

Thanks,
Brian

@gafter

This comment has been minimized.

Copy link
Member

gafter commented Jan 3, 2018

No, we will not have options that so blatantly change the behavior of existing code.

@bchavez

This comment has been minimized.

Copy link

bchavez commented Jan 3, 2018

Not even if it's an opt-in compiler flag? :(

@scalablecory

This comment has been minimized.

Copy link

scalablecory commented Jan 3, 2018

@bchavez comments are to discuss the issue at hand, not to propose entirely different feature requests. But as @gafter more eloquently stated, that is a terrible idea.

@bchavez

This comment has been minimized.

Copy link

bchavez commented Jan 3, 2018

@scalablecory No, it's not a terrible idea, especially when it's an opt-in feature. I'd be happy to create a new issue for discussion about it if that's more appropriate instead of commenting on existing string issues.

@tannergooding

This comment has been minimized.

Copy link
Member

tannergooding commented Jan 3, 2018

Not even if it's an opt-in compiler flag? :(

@bchavez, Compiler switches which change the semantics of your code are generally frowned upon.

There is really only 1 switch that does that today (/checked[+|-]) and it has existed since v1 of the compiler and enables or disables overflow checking, for your entire assembly (the only other option would have been to make one the default, likely checked, and require the user to explicitly opt-out of it where needed).

An important feature of C# is that you can take any given source code file, read it, and will understand that "Hello, {name}" won't expand, but $"Hello, {name}" will (and you can do this with practically any language construct).

@Joe4evr

This comment has been minimized.

Copy link

Joe4evr commented Jan 3, 2018

There is really only 1 switch that does that today (/checked[+|-]) and it has existed since v1 of the compiler and enables or disables overflow checking for your entire assembly

And even then, you can explicitly state to use checked/unchecked math at the source code level regardless of the switch value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment