Proposal: Simple changes to vastly improve FormattableString #682
Replies: 7 comments
-
I don't understand your Implementation section at all. Also, what's wrong with |
Beta Was this translation helpful? Give feedback.
-
For scenarios where you really want to avoid all unnecessary allocations (DSP code, or also in Unity3D) that can make a huge difference. In my example implementations I try to avoid allocating a FormattableString as well as an array for the arguments by letting the compiler create a suitable value-type. |
Beta Was this translation helpful? Give feedback.
-
Could you clarify what exactly are the options you're proposing, and, since one of the goals is to avoid allocations, how do they compare in that regard with alternative approaches, like using I especially don't understand how is |
Beta Was this translation helpful? Give feedback.
-
Except for very expensive inline expressions within interpolated strings, you still end up allocating a function that wraps over the locals used. So it probably saves you a bunch sometimes, but not much most of the time. If you are really worried about allocation performance, you'd be better off surrounding the log method invocation with an if statement that tests whether you should be emitting to the log at all. That way, no allocations occur, and you can use the interpolated string as is. |
Beta Was this translation helpful? Give feedback.
-
This proposal blockades more efficient implementations of the rare conditional expression evaluation problem. e.g. I made a toy programming language that had a expr1;
// dtrace("some string", a, foo())
// is syntax sugar for:
if (isTracing)
print("some string", a, foo());
expr2;
expr3;
return; And the way it was actually implemented was that the code would generate something akin to: expr1;
expr2; // this instruction
_expr3:
expr3;
return;
...
_debugtrace:
expr2;
print("some string", a, foo());
goto _expr3; And when expr1;
goto _debugtrace; // gets patched to this
_expr3:
expr3;
return;
...
_debugtrace:
expr2;
print("some string", a, foo());
goto _expr3; So that the trace logging code would be outside the instruction cache completely in the common case of no trace logging. |
Beta Was this translation helpful? Give feedback.
-
If so much stress is put on efficiency, why not use the simplest method already available: interface ILogger
{
ILevelLogger Debug { get; }
ILevelLogger Trace { get; }
ILevelLogger Verbose { get; }
ILevelLogger Info { get; }
// etc for each level
}
interface ILevelLogger
{
void Msg(string message);
void Exc(string message, Exception exception);
// any other methods you want
}
// usage
ILogger Log = GetLogger();
var stuff = DoStuff();
Log.Debug?.Msg($"Stuff done, max result: {stuff.Max()}");
Profit! |
Beta Was this translation helpful? Give feedback.
-
Stuctured logging is fun. Wrong(GC object created, should be replaced with several Appends)
People think they to Or is next right?
Wrong - structure does not get into index:
People think they do structured logging, but they do not. Right - structure get into index:
? - structure gets into index, better refactoring, but long string and GC
Should I write for each method something like ConclusionC# or BCL must be improved. Interpolation should have API which is used. In StringBuilder or Microsoft Extensions Logging. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I designed this idea with full backwards compatibility in mind, since I know that the design team wants to (or rather "has to") keep the old code around.
There are a variety of problems regarding string interpolations
and obviously many people have the same issues with it. (see: #675 https://github.com/dotnet/roslyn/issues/12336 #177 )
Issue
The main issue here is performance (which is terrible when FormattableString is used in trace-logging).
Objects get allocated even when a log level is turned of.
Expressions inside the interpolations are evaluated even when their results are not needed.
Proposal
Introduce a mechanic that can exist side-by-side with FormattableString, so people who want to override things and create their own
FormattableStringFactory
for whatever reason, can still do so.However it seems like a vast majority of people want something different from string interpolation.
I will roughly outline how I imagine that could work and I'd be very happy to hear your thoughts and suggestions.
Intended usage scenario
After reading through a ton of comments on the issues with string interpolation and FormattableString
I feel confident in saying that most people imagine a usage-scenario similar to this:
log.Info($"Some string {num.SomeMethod(x)} abcdef");
We do not want the interpolation (
num.SomeMethod(x)
) to be executed ifInfo()
decides that it doesn't want to actually output the message.That means
Info
has to take some sort of description of the string interpolation instead of the fully evaluated arguments + the format string.Manually checking like
if(log.IsInfoEnabled) log.Info(...);
is really tiresome and makes the code larger for no real reason.Currently the best way to do this is to simply not use string-interpolation at all, which is sad
and actually doesn't even avoid the problem of calculating things when they're not needed.
log.Info("current way of doing this {0}, {1}, {2}", a,b c);
There are a lot of scenarios where we have debug/trace/verbose logging and when those get disabled we don't want to evaluate expressions that end up not being used.
Goals
string.Format
ourselves with whatever culture we want (or maybe use a StringBuilder or something instead, if one wants to do that!).Implementation
When a interpolation is calling a method (like in the example above), then the expression gets refactored into a real method (just like lambda expressions). A delegate is then passed to the
Info
function.The
Info
method could be declared like one of the following examples:I'm not sure which one of those methods would be easiest to implement or fulfill the proposed goals best, but I'm sure that together we can come up with something that will actually satisfy the majority of people.
Beta Was this translation helpful? Give feedback.
All reactions