For what is worth, I have one small piece of advice for you guys: Please don't be so paranoid about breaking changes. The "field" keyword should have been part of the language since auto-properties have been introduced. As a person who's currently in charge of maintaining roughly a million lines of C# code, I would much rather have our team spend a few days migrating to a new version than end up working with a language full of half-baked mishmash of stuff.
I'd have called the attribute "OverloadResolutionOrder". I find order to be more easily understood than priorities. So you would read it as "this is the first overload I wanna pick when resolving them".
The lock statement and being able to treat every object as a lock was one of many things in C# 1.0 directly copied from Java. And it probably shouldn't have been because it never really made sense there either.
Agreed, was always kind of confusing. Esp in scenarios when you had to create a new object() only for the purpose of locking. With the new Lock class, it's more explicit. However, it was nice that you could lock e.g. directly on the existing collection you were accessing ... now you would need to make an addition *Lock* instance, using a slightly more memory, but with potentially better performance.. But traditional locking still works, so it's a tradeoff.
Are you telling me you added Lock instead of lock and it still does not support that I call my async methods via await keyword in there and I still have to use SemaphoreSlim? I wouldn't be proud of that and I really hope that I am wrong here...
The *lock* keyword is a very low-level construct (with very high performance, even more now with the new *Lock* class) that works directly on a thread. If you look into how async actually works, you will see why you cannot await inside a lock, and why higher-level constructs are needed for that.
Too bad EE didn't make the cut, but I'm only half sad about it. Would have been need if we got the syntax with properties in the first iteration so that we can slowly phase out the old code and be future-ready. Yeah, I have to admit, I'm not a fan that the extension name is not optional in the syntax (in 99% you really don't care about the name of the class), but honestly a bit more verbosity for a clean syntax with a future first-class type inspires as much hope as an interface type constraint would do 🙂
Such a nice feature but .. How come "allows ref struct" is not the default? Why would anyone want to box "T" as "IDisposable" inside a function which requires "T: IDisposable" as an argument, not a boxed "IDisposable"? What is the point? This choice of the default will lead to having "allows ref struct" repeated million times in the standard library. Next, library authors will have to add it everywhere.
I would assume, that the decision was made to have it this way so that there isn't change in default functionality that would cause breaking changes. When your designing something for others to use, it's better to have them make all their updates when they choose to opt in, not force it upon them with default behavior changing unexpectedly. That's why they are so cautious with the new field keyword
if you allow ref structs on your type paramter, then you only can do things with instances of your generic type that are allowed for ref structs, i.e. no allocations of that type on the heap. If that were the default, 99% of existing generic methods and types would need to be annotated to not allow them. All common generic collections, nearly all LINQ methods all would need to specify that they don't allow it. And it wouldn't be much different for the code written by most .NET devs. It would also break nearly every existing .NET code base.
Yeah, the original style guide for C# requires m_ and s_ prefixes, personally I prefer an underscore by it's own as well, so people actually following best practices should have no issues at all.
I've been using underscores for fields 1.) because I've seen the .NET source uses this convention (mostly) 2.) don't need *this* while still knowing it's a field 3.) can't mix it up with local variables. Not a big fan of the s_ or m_ prefixes though
@@mar_sze "s_", "m_", and "g_" carried over from C, and C++, where you can mix global, static, and member scope variables; it instantly showed you the scope of the variable you are using. When writing PInvoke wrappers, there's usually a need for standardisation with the underlying library, at least for the internals, while you modernise the public API surface of the assembly. Same when porting projects from lower level languages into C#. For many, copypasta is production worthy, without a code clean pass. You see so many wrapper libraries, and ports that use camel case public methods, and screaming snake case enums.
You could force using the *ImmutableArray overload* like this in the examples about collection params: Disposer.DisposeAll(ImmutableArray.Create([new ("Hello"), new("World")]));
I mean if you wanna see what is on the screen, you use the normal mode. If you wanna look like a hacker while don't have a clue what is happening in your code: you switch to dark mode. :)
The big features didn't arrive - all those improvements are perf related. In other words, you don't need to use them, you can still kill the environment with pollution by using excessive amounts of power with your long outdated code ;-)
It's all backwards compatible? Why would you dislike progress? Not only that, newer versions of .NET are faster, so upgrading without changing anything, should yield better performance (generally speaking). I can't think of any negatives to an annual STS, and biennial LTS release schedule.
The `allow ref struct` is an amazing addition!
For what is worth, I have one small piece of advice for you guys: Please don't be so paranoid about breaking changes. The "field" keyword should have been part of the language since auto-properties have been introduced. As a person who's currently in charge of maintaining roughly a million lines of C# code, I would much rather have our team spend a few days migrating to a new version than end up working with a language full of half-baked mishmash of stuff.
interesting and clear session! thanks. The word "field" has lost all meaning in my head tho 😅😅
This is part of the reason why explicitly declared fields in a class, struct, etc. should be prefixed with the underscore character.
I'd have called the attribute "OverloadResolutionOrder". I find order to be more easily understood than priorities. So you would read it as "this is the first overload I wanna pick when resolving them".
Now, all that's left is "extend everything" in .NET 10, and C# will finally be perfect.
The lock statement and being able to treat every object as a lock was one of many things in C# 1.0 directly copied from Java. And it probably shouldn't have been because it never really made sense there either.
Agreed, was always kind of confusing. Esp in scenarios when you had to create a new object() only for the purpose of locking. With the new Lock class, it's more explicit. However, it was nice that you could lock e.g. directly on the existing collection you were accessing ... now you would need to make an addition *Lock* instance, using a slightly more memory, but with potentially better performance.. But traditional locking still works, so it's a tradeoff.
Where can I buy a shirt like Mads wears? Amazon link?
Are you telling me you added Lock instead of lock and it still does not support that I call my async methods via await keyword in there and I still have to use SemaphoreSlim? I wouldn't be proud of that and I really hope that I am wrong here...
These two fullfill fundamentally different usecases. How about you get into why it is not possible to use await inside a lock statement?
The *lock* keyword is a very low-level construct (with very high performance, even more now with the new *Lock* class) that works directly on a thread. If you look into how async actually works, you will see why you cannot await inside a lock, and why higher-level constructs are needed for that.
Too bad EE didn't make the cut, but I'm only half sad about it. Would have been need if we got the syntax with properties in the first iteration so that we can slowly phase out the old code and be future-ready. Yeah, I have to admit, I'm not a fan that the extension name is not optional in the syntax (in 99% you really don't care about the name of the class), but honestly a bit more verbosity for a clean syntax with a future first-class type inspires as much hope as an interface type constraint would do 🙂
Such a nice feature but ..
How come "allows ref struct" is not the default? Why would anyone want to box "T" as "IDisposable" inside a function which requires "T: IDisposable" as an argument, not a boxed "IDisposable"? What is the point?
This choice of the default will lead to having "allows ref struct" repeated million times in the standard library. Next, library authors will have to add it everywhere.
I would assume, that the decision was made to have it this way so that there isn't change in default functionality that would cause breaking changes. When your designing something for others to use, it's better to have them make all their updates when they choose to opt in, not force it upon them with default behavior changing unexpectedly. That's why they are so cautious with the new field keyword
if you allow ref structs on your type paramter, then you only can do things with instances of your generic type that are allowed for ref structs, i.e. no allocations of that type on the heap.
If that were the default, 99% of existing generic methods and types would need to be annotated to not allow them.
All common generic collections, nearly all LINQ methods all would need to specify that they don't allow it. And it wouldn't be much different for the code written by most .NET devs.
It would also break nearly every existing .NET code base.
Why “field” and not a “keyword” such as @@ or similar which does not generate a breaking change. 😞
This is why private fields called "field" should be called "_field".
Yeah, the original style guide for C# requires m_ and s_ prefixes, personally I prefer an underscore by it's own as well, so people actually following best practices should have no issues at all.
I've been using underscores for fields 1.) because I've seen the .NET source uses this convention (mostly) 2.) don't need *this* while still knowing it's a field 3.) can't mix it up with local variables. Not a big fan of the s_ or m_ prefixes though
@@mar_sze "s_", "m_", and "g_" carried over from C, and C++, where you can mix global, static, and member scope variables; it instantly showed you the scope of the variable you are using. When writing PInvoke wrappers, there's usually a need for standardisation with the underlying library, at least for the internals, while you modernise the public API surface of the assembly. Same when porting projects from lower level languages into C#. For many, copypasta is production worthy, without a code clean pass. You see so many wrapper libraries, and ports that use camel case public methods, and screaming snake case enums.
You could force using the *ImmutableArray overload* like this in the examples about collection params:
Disposer.DisposeAll(ImmutableArray.Create([new ("Hello"), new("World")]));
This is not "forcing" the overload, you are just "using" it by using the exact type, at the expense of more verbose code.
Are they even engineers if they’re not even using dark mode!
I mean if you wanna see what is on the screen, you use the normal mode. If you wanna look like a hacker while don't have a clue what is happening in your code: you switch to dark mode. :)
I initially agreed then I remembered that my most productive years were spent with light mode and Eclipse + Visual Studio around 2010 😩😩😩
C# looks aweful in dark mode imho, never use it.
With params Span as method parameter, yield does not work. Shameless
This is by design, have a look at how iterator methods are implemented.
Please stop for 1-2 years. Projects can't keep up.
No, please continue the great work. If you can't keep up that ok, none of these features break anything.
It's okay, you can ignore it
The big features didn't arrive - all those improvements are perf related. In other words, you don't need to use them, you can still kill the environment with pollution by using excessive amounts of power with your long outdated code ;-)
It's all backwards compatible? Why would you dislike progress?
Not only that, newer versions of .NET are faster, so upgrading without changing anything, should yield better performance (generally speaking).
I can't think of any negatives to an annual STS, and biennial LTS release schedule.
There's barely anything in C# 13, so this ain't an issue anyways ^^