I think it's important to point out that .NET 6 interpolated strings are now compiled to that new `ref struct` type that is implicitly cast to string. Realizing this made understanding this topic much easier for me. Other than that, thanks for the explanation!
I have long saved development videos, but only the very best -- videos with content that is useful, interesting, high-quality, and not trivially found with a web search. I find that list has grown by nearly every video I have seen on your channel. Your to-the-point, in-depth, not-afraid-to-be-technical format and your passionate approach to real world challenges and solutions, acknowledging how awesome C# is but without the immature wall of isolationism developers often build around their favorite solutions, is prime-grade TH-cam content.
Whoa, I haven't been following closely the more recent additions to C# since 10 but man... it's turning out to be one of my favorite updates. Just discovered InterpolatedStringHandlers (and your video) today but the mention of the CallerArgumentExpression is another jawdropping addition to me. That actually solves a problem I had for a feature I needed to implement. Looks like I'll need to go back and look through all the changes to see what else I'm missing.
What I don't like about features like these is that they have no contract on declarations/definitions. They are not implementing an interface or extending a class, or using some sort of other way to ensure, that you're implementing such features correctly. The same is with async/await and GetAwaiter/Awaiter class, or the Deconstruct method. It's basically "convetion-based". Other than that, I love language features, which compile into something more, but still let you customize what it compiles into. It makes the code clean, more readable, but still optimized. I believe it's also possible to customize the async method builder, would love a video about that. Thanks for great content!
This is a good point and unfortunately Microsoft has a good counter argument. The reason .NET doesn't use many interfaces for their classes is for backwards compatibility. They're afraid an interface change will break millions of lines of code that people have written and they weren't able to come up a good alternative solution at the time.
It's great to see how your voice and facials expressions change when you are showing something as cool as this. It makes feel the one listening to be excited about what you are showing too. Thanks for showing this level of enjoyment and keep up the good work.
I'm curious if entity framework's latest iterations have applied this kind of optimization considering the massive amount of string building or interpolating involved in creating sql statements.
I have an implementation for logging ^^. You can pass a normal interpolated string to a log method and it will generate a state to create the message or provide all values for structured logging. The performance is not as good as generated logging (you explained it in your last video) and for a "real world" software I would still use the generated logging, but it's cool :D And it would be possible to create SQL statements in code with string interpolation and nobody can "forget" the parameters because the handler adds them automatically.
I love this, can see how this would be very beneficial for logging conditionally and enabling logging middlewares to determine if it should log or not instead of having to wrap the code in extensions etc
You shouldn’t use string interpolation for logging. You’re going to lose the structured logging parameters and also when you end up logging for an active log level, it’s gonna use significantly more memory even with this efficient approach.
@@nickchapsas Interpolated string handlers were actually designed with logging as one of the primary use cases. Adding CallerArgumentExpression to your AppendFormatted methods, you can preserve structured logging names. I have a (somewhat) working prototype for Serilog using this, but Serilog makes it a bit more complicated because of custom syntax for structure capturing operators (stringification and destructuring), but it's doable. In terms of memory, you can declare it as a ref struct (like DefaulteInterpolatedStringHandler) and basically avoid all (heap) allocations when logging is turned off :)
@@nickchapsas I agree completely. I was referring to whether we log the whole string or just part of it for non structured logging where we log something regardless just amount/detail. Aldo where do you hear about these features?
@@khellang The problem with CallerArgumentExpression is that is can capture ANY expression, so if in the place of a parameter you place a "DataTime.Now.ToString()" then good luck capturing that in structured logging. It's doable if absolutely everyone that's gonna touch the project is on the same page. The other problem with it is that even if you are to have a conditional shouldAppend check, and then instantiate a handler internally which is still a ref struct, you still actually allocate more memory than you need when logging is actually turned on. You can test that with the Debug.Assert example. When it doesn't fail it doesn't allocate any memory but when it does fail, then the AssertInterpolatedStringHandler ends up allocating more than before. You just can't beat source genned LoggerMessage.Define in performance.
Well, now I wonder if you were to combine what you've shown us here with your logging optimization, would it actually be faster to use string interpolation? Either way, thanks for the video!
You technically can, I was actually planning to show that as an example but the thing is that you don’t wanna do that because you wanna for structured logging to capture the variable consistently so in logging it’s still a bad practice
Have you done a video on IO pipelines and/or channels? I had to use those recently and definitely would like to learn more about them. Thanks for the great vids!
Though all that is saiud in the video here is technically correct, I think it is a very complicated and not very transparent way to achive the goal. I normally use a Func argument in cases, where I want/need to think about performance - run time here. I have inserted a short demo to present my case below (though TH-cam chat formatting isn't good for that). The time improvement in this case is above 99%, though I have not benchmarked memory consumption, so I have no idea if there is a difference here. using System; using System.Diagnostics; namespace StringConcatPerformance { class Program { /// /// Standard way to call method with string argument /// /// If false the message argument will not be used at all /// Represents some string, that it has taken some time to build public static void NormalMethod(bool showMessage, string message) { if (showMessage) Console.WriteLine(message); } /// /// Alternative way to call method with string-returning function argument /// /// If false the messageFunc argument will not be used at all /// A function, that, but only if showMessage argument is true, build and return a string value when called public static void FuncedMethod(bool showMessage, Func messageFunc) { if (showMessage) Console.WriteLine(messageFunc.Invoke()); }
static void Main(string[] args) { // Example of how to call "the old way" and as Func-argument NormalMethod(false, $"This string is created at {DateTime.Now:yyyyMMDD HHmmss.fff}"); FuncedMethod(false, () => $"This string is created at {DateTime.Now:yyyyMMDD HHmmss.fff}"); // Simple Stopwatch times benchmark test. Call both methods a lot of times but never actually use the Message/MessageFunc arguments var calls = 100000; var watch = new Stopwatch(); watch.Reset(); watch.Start(); for (var i = 0; i < calls; i++) NormalMethod(false, $"{i}'th call, {DateTime.Now:yyyyMMDD HHmmss.fff}"); watch.Stop(); var normal = watch.ElapsedMilliseconds;
watch.Reset(); watch.Start(); for (var i = 0; i < calls; i++) FuncedMethod(false, () => $"{i}'th call, {DateTime.Now:yyyyMMDD HHmmss.fff}"); watch.Stop(); var funced = watch.ElapsedMilliseconds;
Firstly, you should be using BenchmarkDotnet if you wanna get any reliable benchmark results. The problem with your code is the closures you create. It's not just about the speed but also, or even more, about the memory.
Damn, you are pretty knowledgeable. Only be careful with microbenchmarks, loop alignment is a big thing in this scenarios. Especially when comparing .net 5 (basically no loop alignment) and 6 (optimized loop alignment). In .net 5, changing the order of methods in the class can lead to different benchmark results.
That seems like a lot of machinery to inline an if-statement... Kotlin has inline functions which inline lambda arguments as well. So: require(mybool){ "Failed!" } ... will accomplish the same as the message handler in C#. However, what really is nice in C# are the attributes to fetch the caller class name, caller method name and caller parameter expression. Simple and neat, I wish Kotlin had that.
It's more than just inlining the if statement. You can also write custom handling for each type, for example in the case of string interpolcating a sql query. It can do way more things than this very basic example. I do like Kotlin's approach this this problem though. It just doesn't read as nice.
Yeap, I use statement body because of the folding. Expression body will get out of screen and be hard to show in the video, but you’re right, you would use expression body there
Cool. Hey Nick, can you help me understand how you saved memory? Okay you did that for saving the space of string provided in method... but what about the extra space you allocated for your extra class?
The EnsureInterpolatedHandler is a struct which only wraps the default C# handler struct. This wrapper only added behavior, not data, so no additional memory should be needed due to them being structs instead of classes (so no pointers to other heap-allocated objects). Please do correct me if I'm wrong though, would really love to dive deeper into this C# topic :D
It's not about EnsureInterpolatedHandler being a ref struct but also about the AppendFormatted method using a generic which will prevent the boxing that happen with the string.Format method
AFAIK: string.Format is the same as it was before C#10. string.Format has already been making use of the ISpanFormattable interface before it was made public.
I think you should also show your viewers the ISpanFormattable interface and the memory implications of implementing it in classes and structs that are used in string interpolation
This code does however evaluate all the expressions in the message passed in. For example if you do: static bool flag = true; EnsureThan.IsTrue(1==1, $"blabla {() =>{ flag = false; return "flag was set to false."; }}); Assert.IsTrue(flag); Then this test would actually fail. I was playing around with it a little and I was able to get this test to work with something like: public void IsTrue(bool condition, [InterpolatedStringHandlerArgument("", "condition")] InterpolatedStringHandlerPositiveChecks handler) This has the sad downside of not working with static functions, so I had to use a singleton there.
This is not correct. If the `out` parameter in the constructor is false after construction, no part of the interpolated string handler will be evaluated.
Nick, After watching your channel for so long, the quality of others just does not cut it for me. Can you make a series on Golang? We all win. I’ll send you a six pack of beer.
I’m new to C# and this level of programming. Where do you recommend I start so that I can understand what you mean when you refer to heap vs stack, references, class vs struct, etc. ?
@@briumphbimbles uhm, functional form of programming for example? :) I mean when were you worry about these things in a typescript or a python code last time? :D
If I noticed correctly, the code that you’ve written in the EnsureInterpolatedStringHandler constructor was actually inlined into the caller. If so, does it make sense to make this type “ref struct” as it is not instantiated anyway?
The "ref struct" guards against boxing the value into the heap. So, it is just a safeguard to ensure that the code in the handler will not box it, to ensure that no unwanted allocations will occur, so yes it makes sense to use a "ref struct".
Hi. Great video as always! I wanted to ask you about a problem specific to programmers, but not code :) What chair are you using? If I'm not mistaken, the logo looks like Secretlab. Is it good for long day's work? I am considering some ergonomic chairs, but they tend to be very expensive and I don't think I should rush with such a big investment. I want to use something that will keep me healthy for years to come and am wondering how it's been treating you so far. Thank you for all the videos. I really enjoy learning about topics I never encounter on my job, really is a breathe of fresh air! Keep up the great work!
It’s as good as gaming chairs get but to be honest, a used Aeron would probably be a better investment. Im very happy with it, especially with their new softer seat, but I would try before I buy
@@nickchapsas do you agree that services should be scoped unless they need a state insde? The author of MediatR says that we need to do so and the extra object allocation is miserable
Hello Nick, nice video again. Can you explain why private DefaultInterpolatedStringHandler should not be readonly? If it is as suggests Visual studio then ToString returns an empty string. 🙂 Thanks !
In the optimized version of the method when the condition is successful, he removed the reference to the default handler as it wasn't needed so had to be able to change that. Though it could have easily be rewritten in such a way that it could be readonly by conditionally setting it in the ctor.
It seems like string.Concat() could be similarly optimized to prevent the boxing by a bunch of generic overloads. Why hasn't this been done? Has it been proposed and rejected?
You have to balance that memory against the explosion of generic specialization the JIT will need to do to have all the versions of `string.Concat` that you'll end up using. Just given 3 arguments with different types, there are 3^2 = 9 ways of ordering those arguments, and there are way, way more than 3 types in any given .NET program. You'd save memory with boxing, but end up losing it all to the JIT for different method compilations anyway.
Hi Nick, first of all excellent video, congratulations! I’ve an off-topic request: I was recently developing a specific service and I came across that the class in question was getting a lot of dependency injections. After searching a bit I saw that the Facade design pattern could somehow help me, but some people say that it violates some SOLID principles. Could you make a video about this design pattern? Thank you so much in advance.
I feel like a total noob when I watch your videos. I mean I'm stilla student, but I would like to get to your lvl some day :) Do you have any beginner to intermediate to pro courses for C# and .Net planned?
You shouldn’t use string interpolation when logging. You should do structured logging instead. It doesn’t allocate any memory with source generators or the delegate approach
@@nickchapsas For what it's worth, depending on your setup, you can throw a noise-gate on your recording software to "cheaply" mitigate issues like this.
@@farsidesc4044 Ok so there was actually a noise gate and it was making it less noticable when I was talking. I added the CloudLifter again into the mix and I am getting clean sound so it was probably a loose XLR connection.
Hey great video, your English is really good. Just a couple of tips, you always speak fast and not very clearly at the start of your videos and it's hard to know what you're saying because of the Greek accent (but the rest of the video is fine). In this video @10:25 you pronounce "Exception" as "Expression". Your videos are great and this isn't meant as an insult at all, just something to help you improve.
Hey thanks! The fast intro is a bit of a meme at this point which is why I’m not slowing it down. In regards to the expression thing, I tend to read words and numbers wrong. Sometimes then number will be 430 and I will say 43 for no reason and it happens with words as well. I usually catch it in edit but I don’t wanna ADR it so I usually just add a text annotation in the video
Still annoying that I have to $ before the string to use it. I guess that is for the backward compatibility with the old source code, but when a language gets decades old like Java or C#, I think maybe at some point it needs to give up that compatibility for the greater good. Those who still have old source code could use set some sort of compiler option to compile it in the old way, or use some sort of automated tool to "upgrade" the code to a newer syntax.
@@nickchapsas An interface cannot force a constructor signature. And a base class won't work, since the base class has to be part of the BCL. And this is a compiler (roslyn) trick wich is applied before having access to any of the BCL classes. Same goes for example if you want to use IAsyncDisposable on a target framework which does not have that interface. You can grab it from a nuget package, or define that interface in your own project. Since it's compiler magic, this still works on older frameworks. At least, I 'think' that's the reason :)
I think it's important to point out that .NET 6 interpolated strings are now compiled to that new `ref struct` type that is implicitly cast to string. Realizing this made understanding this topic much easier for me. Other than that, thanks for the explanation!
I have long saved development videos, but only the very best -- videos with content that is useful, interesting, high-quality, and not trivially found with a web search.
I find that list has grown by nearly every video I have seen on your channel. Your to-the-point, in-depth, not-afraid-to-be-technical format and your passionate approach to real world challenges and solutions, acknowledging how awesome C# is but without the immature wall of isolationism developers often build around their favorite solutions, is prime-grade TH-cam content.
Whoa, I haven't been following closely the more recent additions to C# since 10 but man... it's turning out to be one of my favorite updates. Just discovered InterpolatedStringHandlers (and your video) today but the mention of the CallerArgumentExpression is another jawdropping addition to me. That actually solves a problem I had for a feature I needed to implement. Looks like I'll need to go back and look through all the changes to see what else I'm missing.
What I don't like about features like these is that they have no contract on declarations/definitions. They are not implementing an interface or extending a class, or using some sort of other way to ensure, that you're implementing such features correctly. The same is with async/await and GetAwaiter/Awaiter class, or the Deconstruct method. It's basically "convetion-based". Other than that, I love language features, which compile into something more, but still let you customize what it compiles into. It makes the code clean, more readable, but still optimized. I believe it's also possible to customize the async method builder, would love a video about that. Thanks for great content!
This is a good point and unfortunately Microsoft has a good counter argument. The reason .NET doesn't use many interfaces for their classes is for backwards compatibility. They're afraid an interface change will break millions of lines of code that people have written and they weren't able to come up a good alternative solution at the time.
@@briankarcher8338 Isn't this what default implementation for
It's great to see how your voice and facials expressions change when you are showing something as cool as this. It makes feel the one listening to be excited about what you are showing too. Thanks for showing this level of enjoyment and keep up the good work.
As clear as it ever could be! Great job, thank you!
I'm curious if entity framework's latest iterations have applied this kind of optimization considering the massive amount of string building or interpolating involved in creating sql statements.
This is some really insane (read: awesome) stuff. Thanks for showing.
I have an implementation for logging ^^.
You can pass a normal interpolated string to a log method and it will generate a state to create the message or provide all values for structured logging.
The performance is not as good as generated logging (you explained it in your last video) and for a "real world" software I would still use the generated logging, but it's cool :D
And it would be possible to create SQL statements in code with string interpolation and nobody can "forget" the parameters because the handler adds them automatically.
Να ΄σαι καλά ρε Νικόλα για την γνώση που προσφέρεις!!!!!
I love this, can see how this would be very beneficial for logging conditionally and enabling logging middlewares to determine if it should log or not instead of having to wrap the code in extensions etc
You shouldn’t use string interpolation for logging. You’re going to lose the structured logging parameters and also when you end up logging for an active log level, it’s gonna use significantly more memory even with this efficient approach.
@@nickchapsas Interpolated string handlers were actually designed with logging as one of the primary use cases. Adding CallerArgumentExpression to your AppendFormatted methods, you can preserve structured logging names. I have a (somewhat) working prototype for Serilog using this, but Serilog makes it a bit more complicated because of custom syntax for structure capturing operators (stringification and destructuring), but it's doable. In terms of memory, you can declare it as a ref struct (like DefaulteInterpolatedStringHandler) and basically avoid all (heap) allocations when logging is turned off :)
@@nickchapsas I agree completely. I was referring to whether we log the whole string or just part of it for non structured logging where we log something regardless just amount/detail. Aldo where do you hear about these features?
@@khellang The problem with CallerArgumentExpression is that is can capture ANY expression, so if in the place of a parameter you place a "DataTime.Now.ToString()" then good luck capturing that in structured logging. It's doable if absolutely everyone that's gonna touch the project is on the same page. The other problem with it is that even if you are to have a conditional shouldAppend check, and then instantiate a handler internally which is still a ref struct, you still actually allocate more memory than you need when logging is actually turned on. You can test that with the Debug.Assert example. When it doesn't fail it doesn't allocate any memory but when it does fail, then the AssertInterpolatedStringHandler ends up allocating more than before. You just can't beat source genned LoggerMessage.Define in performance.
Well, now I wonder if you were to combine what you've shown us here with your logging optimization, would it actually be faster to use string interpolation? Either way, thanks for the video!
You technically can, I was actually planning to show that as an example but the thing is that you don’t wanna do that because you wanna for structured logging to capture the variable consistently so in logging it’s still a bad practice
Have you done a video on IO pipelines and/or channels? I had to use those recently and definitely would like to learn more about them. Thanks for the great vids!
Thanks for explaining. Great that they fixed it!
Though all that is saiud in the video here is technically correct, I think it is a very complicated and not very transparent way to achive the goal.
I normally use a Func argument in cases, where I want/need to think about performance - run time here.
I have inserted a short demo to present my case below (though TH-cam chat formatting isn't good for that).
The time improvement in this case is above 99%, though I have not benchmarked memory consumption, so I have no idea if there is a difference here.
using System;
using System.Diagnostics;
namespace StringConcatPerformance
{
class Program
{
///
/// Standard way to call method with string argument
///
/// If false the message argument will not be used at all
/// Represents some string, that it has taken some time to build
public static void NormalMethod(bool showMessage, string message)
{
if (showMessage) Console.WriteLine(message);
}
///
/// Alternative way to call method with string-returning function argument
///
/// If false the messageFunc argument will not be used at all
/// A function, that, but only if showMessage argument is true, build and return a string value when called
public static void FuncedMethod(bool showMessage, Func messageFunc)
{
if (showMessage) Console.WriteLine(messageFunc.Invoke());
}
static void Main(string[] args)
{
// Example of how to call "the old way" and as Func-argument
NormalMethod(false, $"This string is created at {DateTime.Now:yyyyMMDD HHmmss.fff}");
FuncedMethod(false, () => $"This string is created at {DateTime.Now:yyyyMMDD HHmmss.fff}");
// Simple Stopwatch times benchmark test. Call both methods a lot of times but never actually use the Message/MessageFunc arguments
var calls = 100000;
var watch = new Stopwatch();
watch.Reset();
watch.Start();
for (var i = 0; i < calls; i++)
NormalMethod(false, $"{i}'th call, {DateTime.Now:yyyyMMDD HHmmss.fff}");
watch.Stop();
var normal = watch.ElapsedMilliseconds;
watch.Reset();
watch.Start();
for (var i = 0; i < calls; i++)
FuncedMethod(false, () => $"{i}'th call, {DateTime.Now:yyyyMMDD HHmmss.fff}");
watch.Stop();
var funced = watch.ElapsedMilliseconds;
Console.WriteLine(@$"{calls} calls Normal: {normal} msec, Funced: {funced} msec");
Console.WriteLine(@$"Difference: {(100 - 100.0 * funced/normal):N02}% saved with FuncedMethod");
}
}
}
Firstly, you should be using BenchmarkDotnet if you wanna get any reliable benchmark results. The problem with your code is the closures you create. It's not just about the speed but also, or even more, about the memory.
Thanks again for your videos, Nick! You help me a lot.
Damn, you are pretty knowledgeable.
Only be careful with microbenchmarks, loop alignment is a big thing in this scenarios.
Especially when comparing .net 5 (basically no loop alignment) and 6 (optimized loop alignment).
In .net 5, changing the order of methods in the class can lead to different benchmark results.
thanks for the great video!
The only thing I know how to code is a window with an exit function in Visual Basic on Windows XP, this video was entertaining yet absolute gibberish.
That seems like a lot of machinery to inline an if-statement... Kotlin has inline functions which inline lambda arguments as well. So:
require(mybool){ "Failed!" }
... will accomplish the same as the message handler in C#. However, what really is nice in C# are the attributes to fetch the caller class name, caller method name and caller parameter expression. Simple and neat, I wish Kotlin had that.
It's more than just inlining the if statement. You can also write custom handling for each type, for example in the case of string interpolcating a sql query. It can do way more things than this very basic example. I do like Kotlin's approach this this problem though. It just doesn't read as nice.
Those method forwards are a great candidate for expression body over statement body 👀
Yeap, I use statement body because of the folding. Expression body will get out of screen and be hard to show in the video, but you’re right, you would use expression body there
Cool. Hey Nick, can you help me understand how you saved memory? Okay you did that for saving the space of string provided in method... but what about the extra space you allocated for your extra class?
The EnsureInterpolatedHandler is a struct which only wraps the default C# handler struct.
This wrapper only added behavior, not data, so no additional memory should be needed due to them being structs instead of classes (so no pointers to other heap-allocated objects).
Please do correct me if I'm wrong though, would really love to dive deeper into this C# topic :D
It's not about EnsureInterpolatedHandler being a ref struct but also about the AppendFormatted method using a generic which will prevent the boxing that happen with the string.Format method
Does this affect String.Format in any way, or is String.Format (even more of a) legacy feature?
AFAIK: string.Format is the same as it was before C#10. string.Format has already been making use of the ISpanFormattable interface before it was made public.
Doesnt this completely change your recent logging video? Amazing stuff. Thanks for sharing
No, the recent video is still more efficient than this because you don't allocate anything again no matter the log level.
I think you should also show your viewers the ISpanFormattable interface and the memory implications of implementing it in classes and structs that are used in string interpolation
Is there a similar extension for VS that shows what we see on 3:11
Huh... I USED to think that I was a C#/.NET expert... LOL
That's a lot of black magic and long names. I understand that ref struct can have interfaces but will be great to be able to have actual types.
This code does however evaluate all the expressions in the message passed in. For example if you do:
static bool flag = true;
EnsureThan.IsTrue(1==1, $"blabla {() =>{
flag = false;
return "flag was set to false.";
}});
Assert.IsTrue(flag);
Then this test would actually fail. I was playing around with it a little and I was able to get this test to work with something like:
public void IsTrue(bool condition, [InterpolatedStringHandlerArgument("", "condition")] InterpolatedStringHandlerPositiveChecks handler)
This has the sad downside of not working with static functions, so I had to use a singleton there.
This is not correct. If the `out` parameter in the constructor is false after construction, no part of the interpolated string handler will be evaluated.
Prefect
Nick, After watching your channel for so long, the quality of others just does not cut it for me. Can you make a series on Golang? We all win. I’ll send you a six pack of beer.
Άψογος!
I’m new to C# and this level of programming. Where do you recommend I start so that I can understand what you mean when you refer to heap vs stack, references, class vs struct, etc. ?
Check this video out: th-cam.com/video/jONSIhMST9E/w-d-xo.html
What form of programming doesnt have references, stacks and heaps?
@@briumphbimbles I mean that it’s never been a concern for me at my level of experience. You couldn’t deduce that or are you being pedantic?
@@danielbocelli No not being pedantic just curious which language you have been using where you thought it wasnt a concern?
@@briumphbimbles uhm, functional form of programming for example? :) I mean when were you worry about these things in a typescript or a python code last time? :D
If I noticed correctly, the code that you’ve written in the EnsureInterpolatedStringHandler constructor was actually inlined into the caller. If so, does it make sense to make this type “ref struct” as it is not instantiated anyway?
It wasn't inlined. The compiler took that and instantiated the ref struct appropriately, so it is instantiated.
The "ref struct" guards against boxing the value into the heap. So, it is just a safeguard to ensure that the code in the handler will not box it, to ensure that no unwanted allocations will occur, so yes it makes sense to use a "ref struct".
Hi. Great video as always!
I wanted to ask you about a problem specific to programmers, but not code :) What chair are you using? If I'm not mistaken, the logo looks like Secretlab. Is it good for long day's work? I am considering some ergonomic chairs, but they tend to be very expensive and I don't think I should rush with such a big investment.
I want to use something that will keep me healthy for years to come and am wondering how it's been treating you so far.
Thank you for all the videos. I really enjoy learning about topics I never encounter on my job, really is a breathe of fresh air! Keep up the great work!
It’s as good as gaming chairs get but to be honest, a used Aeron would probably be a better investment. Im very happy with it, especially with their new softer seat, but I would try before I buy
Great video. Nick, a quick question about memory efficiency: are you using transient/scoped or singleton services and repositories?
It depends on the backing library
@@nickchapsas do you agree that services should be scoped unless they need a state insde? The author of MediatR says that we need to do so and the extra object allocation is miserable
@@antonmartyniuk It really, heavily depends on your dependencies. I don't use MediatR in high-perf situations anyway so it doesn't matter.
Hello Nick, nice video again. Can you explain why private DefaultInterpolatedStringHandler should not be readonly? If it is as suggests Visual studio then ToString returns an empty string. 🙂
Thanks !
In the optimized version of the method when the condition is successful, he removed the reference to the default handler as it wasn't needed so had to be able to change that. Though it could have easily be rewritten in such a way that it could be readonly by conditionally setting it in the ctor.
Do the Benchmarks also measure the time GC needs to clean up??? While GC is cleaning up, all TASKs get on HOLD.
It does. It measures it as GC time in all generations
Hi Nick, I admire your work a lot. What about Q&A at 100k subs? :D you could make a post with question and choose most liked. Cheers from Poland!
It seems like string.Concat() could be similarly optimized to prevent the boxing by a bunch of generic overloads. Why hasn't this been done? Has it been proposed and rejected?
You have to balance that memory against the explosion of generic specialization the JIT will need to do to have all the versions of `string.Concat` that you'll end up using. Just given 3 arguments with different types, there are 3^2 = 9 ways of ordering those arguments, and there are way, way more than 3 types in any given .NET program. You'd save memory with boxing, but end up losing it all to the JIT for different method compilations anyway.
Hi Nick, first of all excellent video, congratulations! I’ve an off-topic request: I was recently developing a specific service and I came across that the class in question was getting a lot of dependency injections. After searching a bit I saw that the Facade design pattern could somehow help me, but some people say that it violates some SOLID principles. Could you make a video about this design pattern? Thank you so much in advance.
RawCoding does alot of design pattern videos and has one about Facade
th-cam.com/video/xzpp5_ak8Hg/w-d-xo.html&ab_channel=RawCoding
I feel like a total noob when I watch your videos. I mean I'm stilla student, but I would like to get to your lvl some day :) Do you have any beginner to intermediate to pro courses for C# and .Net planned?
How can We use faster string interpolations when logging?
You shouldn’t use string interpolation when logging. You should do structured logging instead. It doesn’t allocate any memory with source generators or the delegate approach
@@fabolt But you shouldn't because you are losing the structured logging parameters
@@fabolt In my experience, they are required in most scenarios.
Sucks about the audio line static. Broken cable?
I noticed it in the video I recorded yesterday while I was editing. I will be investigating what causes it today.
Looks like removing the CloudLifter from the setup clears the sound
@@nickchapsas For what it's worth, depending on your setup, you can throw a noise-gate on your recording software to "cheaply" mitigate issues like this.
@@nickchapsas Don't rule out a bad cable yet. Glad you found the link in the chain though!
@@farsidesc4044 Ok so there was actually a noise gate and it was making it less noticable when I was talking. I added the CloudLifter again into the mix and I am getting clean sound so it was probably a loose XLR connection.
YEEEEEEE
I see that guitar in the background, and am afraid you might be as good playing the guitar as you are with coding ;-)
Wow
tl;dr - They made the compilation more complex but fixed the running code
My brain hurts
Hey great video, your English is really good. Just a couple of tips, you always speak fast and not very clearly at the start of your videos and it's hard to know what you're saying because of the Greek accent (but the rest of the video is fine). In this video @10:25 you pronounce "Exception" as "Expression". Your videos are great and this isn't meant as an insult at all, just something to help you improve.
Hey thanks! The fast intro is a bit of a meme at this point which is why I’m not slowing it down. In regards to the expression thing, I tend to read words and numbers wrong. Sometimes then number will be 430 and I will say 43 for no reason and it happens with words as well. I usually catch it in edit but I don’t wanna ADR it so I usually just add a text annotation in the video
Legit
Still annoying that I have to $ before the string to use it. I guess that is for the backward compatibility with the old source code, but when a language gets decades old like Java or C#, I think maybe at some point it needs to give up that compatibility for the greater good. Those who still have old source code could use set some sort of compiler option to compile it in the old way, or use some sort of automated tool to "upgrade" the code to a newer syntax.
any plans to make a giveway of your courses in a near future? :-)
No plans for a giveaway no
It's a shame that struct cannot be inherited.
i'm lost
Wish that declaration of custom InterpolatedStringHandler would've been inherited from a base class instead of using attribute and compiler magic.
Yeah or an interface, it is a bit tricky as it
@@nickchapsas An interface cannot force a constructor signature. And a base class won't work, since the base class has to be part of the BCL. And this is a compiler (roslyn) trick wich is applied before having access to any of the BCL classes. Same goes for example if you want to use IAsyncDisposable on a target framework which does not have that interface. You can grab it from a nuget package, or define that interface in your own project. Since it's compiler magic, this still works on older frameworks. At least, I 'think' that's the reason :)
@@remcoros We wanted DefaultInterpolatedStringHandler to be a ref struct, which precludes any interface or base type implementation.
C# gets way overcomplicated as time goes on...
Anders Hejlsberg is choking on his coffee. Strongly disagree with this kind o contrivedf compiler level kludge.
Anders was in the design review.