[Proposal] Capture names (or full code) of interpolated values if string interpolation is passed in as a FormattableString
See original GitHub issueThis proposal was already answered on CodePlex with “too late for C#6”, but since C#7 is taking input at the moment, I think it is worth mentioning this again.
Problem:
Current design for FormattableString
is:
public class FormattableString {
public string Format { get; }
public object[] Args { get; }
// ...
}
Consider two following usages:
// Some future Serilog:
log.Information($"Processed {position} in {elapsedMs:000} ms.");
// Some future Dapper:
connection.Execute($"SELECT * FROM T1 WHERE Id = {id}");
In addition to saving the log string, Serilog saves format values as properties on the log entry object. However with current FormattableString
the names of these values (position
, elapsedMs
) would not be available.
Dapper does not really need the names (it can generate parameters named @p1
and @p2
), but proper names can improve readability of SQL traces and general SQL debugging.
And another (weird) use case for capturing names of the provided values:
Argument.NotNull($"{x}"); // doesn't actually need the string at all, but uses arg name/value
Compare this with current:
Argument.NotNull(nameof(x), x); // more verbose, not DRY
Potential solution
Add IReadOnlyList<string> Names { get; }
to the FormattableString
.
Those could be generated based on anonymous class property name algorithm:
1. $"{x}, {y}" // Names = "x", "y"
2. $"{x.Y.Z}" // Names = "Z"
3. $"{x}, {5}" // Names = "x", null
Or just literally contain passed in code as a string, e.g. $"{x+5}" // Names = "x+5"
, though in this case something like Snippets
would be a better name.
Since each call site will have a fixed set of names/snippets, each list can be cached per call site once and reused between calls. This means that even the names/snippets aren’t used, the performance cost would be minimal.
Pros
- Allows frameworks to be more intelligent when generating a new string from
FormattableString
or recording the parameters somewhere. - Gives some unexpected uses to the
FormattableString
by making it a light-weight way to pass identifier-named value – e.g. validation. - If code is passed as as string instead of generating a name, this can be used to create an easily cacheable analog of expression trees (by parsing it with Roslyn etc), and various other kinds of ‘magic’ APIs.
Cons
- If names are generated using anonymous class algorithm, some of them might be null. This might be unexpected – frameworks can provide fallback, but they have to be careful of those cases.
- If full code is passed as a string, analysis has to be careful so that it is not broken by small variations within the code (e.g. as introduced by refactoring).
Issue Analytics
- State:
- Created 9 years ago
- Reactions:7
- Comments:50 (32 by maintainers)
Top GitHub Comments
@gafter The reason is important. The way your original decision was worded strongly discouraged me from providing any Roslyn feedback in the future. I don’t mind the rejection, but why spend my free time doing well-structured proposals to get a single sentence? Which gives me no idea on what I did wrong – or how to avoid wasting your (and my) time again.
I suppose it depends on your situation. If you are overloaded with ideas, then I understand why it doesn’t matter if you lose a few people along the way.
However I’ll still give my two cents on what I would like to see in a proper Roslyn decision:
Fortunately and unfortunately we get more proposals than we can discuss in any depth. Folks on the LDM spend time looking at proposals here on GitHub, and bring up ones that they feel should warrant a discussion. This may be because they agree with the proposal, or feel that it raises a scenario that is worth trying to address, or similar. We call this “championing” a feature. This is our primary filtering mechanism, and it helps us focus our limited time on proposals that have a chance.
I realize how annoying it is to spend time on a proposal and then have it ignored or summarily dismissed. I wish there was a realistic process by which we could formulate a “why not” for every well-worked-out proposal that we do not choose to adopt into the language. Neal closing this issue is the closest we can get - he realizes the issue won’t make it to a discussion, and closes it as a signal to the participants on the thread to help prioritize their efforts.
I’m sorry if this comes off as non-appreciative: it is not! We deeply value the discussions and proposals here, and they have a big influence on where we take the language. This goes for feature proposals, and equally for the many posts pointing out flaws and inconsistencies in proposals - ours and others’. I want to thank everyone who spends time and creative energy here, enriching the discussion and helping drive the languages forward.
If you feel a proposal really deserves our attention and isn’t getting it, I recommend submitting it on UserVoice as well:
https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/category/30931-languages-c https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/category/30933-languages-visual-basic
Whereas the feedback here on GitHub is rich on technical commentary and insights, UserVoice has the crucial benefit of allowing voting. It also tends to reach a more representative set of developers. Top UserVoice suggestions are sure to grab our attention, whether or not we are able to do something about them. In this way, the two forums supplement each other well.
Again, thanks for all the great ideas! I love the intensity, quality and volume of discussion, and it breaks my heart that we (the language designers) cannot engage deeply in all of it.