This content originally appeared on DEV Community and was authored by Edward Miller
C# is very near to a perfect programming language, by my standards. But there are still some rough edges.
There has been much discussion about proposals such as extension types or the field keyword inside getters and setters, which are mostly about convenience.
And there's been a lot of work on source generators and AOT, which is mainly about performance.
But I think we need a focus on correctness. Here are some examples:
Real Nullable Types
The null reference exception is a legacy of the "billion-dollar mistake" that Tony Hoare said he made in the design of the ALGOL W language in 1965. We have been dealing with it ever since.
Nullable types ought to be an authentic part of the type system in C#. They currently appear to be like a thin shim of syntactic sugar that are little more than Roslyn analyzers.
If you make a public function that requires a non-nullable parameter that is a reference type, and call it from another project that doesn't enable nullable types... there is actually nothing stopping the parameter from being filled with null.
No error would be thrown at compile-time or runtime when trying to fill that parameter with a null.
So, despite that you have already clearly specified your intentions, you have to guard your public parameters against null references.
And if you try to detect whether a type is nullable or not, using reflection, then a reference type is going to always be seen as nullable. As far as I know, there is not even a way to write a generic function that detects whether you defined a reference type as non-nullable. Because no matter what you actually do it really is nullable.
All of that works fine for value types, but that still leaves way too much room for covert null reference exceptions.
Better type inference for generics with constraints
Should be able to do complex constraints where one generic type is a collection of another generic type.
see also: https://github.com/dotnet/roslyn/pull/7850
And you should be able to accept generics that are very wide, and could be either enums, reference types, or structs... and either nullable or not.
But currently know of no way to return a nullable generic type that could be either a reference type or an enum. As far as I know, the returned enum won't really be nullable no matter what you do. Likely because the entire nullable types concept isn't actually in the type system.
Exception Type Matching
All possible exception types that can be thrown by a particular function call to be known at compile-time, much like Rust's concept of the Option
type.
Analyzer CA1031 exists specifically to inform the user that they ought not be catching general exceptions.
A better language would be able to show you precisely in the IntelliSense popup all possible exception types that could be thrown, even without the library authors documenting the exceptions with XML comments.
If this were the case this would help the specific kinds of exceptions to be handled in the specific ways that they ought to be, without any fear of unknowns.
And, aside from correctness-oriented improvements, there are some oversights in existing features need to be addressed:
Kotlin-style init
blocks
If you want to add some imperative logic during initialization, you cannot currently use a primary constructor. Kotlin solved this with the init
block. C# should copy that.
see also: https://github.com/dotnet/csharplang/discussions/4025
And some general .NET Framework enhancements are needed in the standard libraries:
Range support in ICollection
This one is super obvious. ObservableCollection
is a great example of where we need it. There have been countless custom implementations of something like ObservableRangeCollection
. Having all of the changes show up in a single CollectionChanged event makes vastly more sense than users falling back to using loops of Add() calls because the framework has this deficiency.
see also: https://github.com/dotnet/runtime/issues/18087
Deserializing interfaces with System.Text.Json
Newtonsoft.Json
supports this by default without much effort on the part of the developer. System.Text.Json
now has some support for "polymorphic deserialization," but it involves a lot of manual intervention on the part of the programmer.
Apparently, there are security concerns around this, and the current approach certainly allows for improved performance. But for quick and dirty stuff, it would be nice to have a simple default that just works for most cases. While still giving some safety valves against attack vectors, like attempting to (de)serialize Exception types.
ConfigureAwait()
improvements
Library authors generally want to use ConfigureAwait(false)
everywhere, but there is no easy way to define this globally. Having the codebase littered with ConfigureAwait(false)
everywhere is ugly, and some async function calls are likely to be overlooked and thus defeat the entire point.
Turning on analyzer CA2007 can help, but you would need to intentionally do so, and know to do so. And it is still annoying.
There must be a better way.
This content originally appeared on DEV Community and was authored by Edward Miller
Edward Miller | Sciencx (2024-07-27T17:53:10+00:00) The main features I want for C#. Retrieved from https://www.scien.cx/2024/07/27/the-main-features-i-want-for-c/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.