7 ms·
As a fellow C# aficionado, what do you think it's lacking right now? The main thing I really would like to see is support for discriminated unions - but outside
by dgritsko 5y ago
As a fellow C# aficionado, what do you think it's lacking right now? The main thing I really would like to see is support for discriminated unions - but outside of that, it's pretty awesome.
- binarynate 5y agoI'd love to see support for structural typing. There are some proposals for that: - https://github.com/dotnet/csharplang/discussions/164 https://github.com/dotnet/csharplang/discussions/164 - https://github.com/dotnet/csharplang/discussions/2548 https://github.com/dotnet/csharplang/discussions/2548
- polskibus 5y agoNullable references are far from what they could be. When you use them a lot, you often have to override compiler with ! because it is too stupid. I’d also like to have better support for const references as in c++. I’d like to see more powerful generics, so that something akin to partial template specialisation is possible without going through boxing and unboxing too much. With regards to safety, well rust has shown what is possible. Async/ await has introduced function colouring which is a kind of bloat. All in all there are many things that could reduce the bloat, instead of some tiny features that help with value types or to optimise some rare case.
- tester756 5y ago>With regards to safety, well rust has shown what is possible. Async/ await has introduced function colouring which is a kind of bloat. I do wonder how much effort it'd require
- jayd16 5y agoPeople call async/await function coloring bloat but I think it's exactly where it needs to be. IMO execution yielding needs to be explicit not implicit for use cases where thread identity matters. How are you going to write a UI framework if thread context can change unexpectedly?
- coder543 5y agoGo doesn't need "coloring bloat", but you can still handle the need to run code on a specific thread using LockOSThread.[0] If you absolutely need your code that interacts with the OS GUI functions to be running on the first thread the OS spawned, the documentation even tells you how to do that. This is an exceptionally low level detail that very few people should ever have to think about. Is there something else you can point to that's pertinent to more developers? Having written Go for years (as well as a good bit of Rust), I love not having to worry about async/await being the concurrency model, and thread identity is never something I think about. With the upcoming Go release that brings generics, I think there are some code patterns that inherently benefit from an async/await style pattern where you spawn several tasks and await their results, so I'm looking forward to having a generic pattern to spawn goroutines that return a value into a Promise... but the infectious nature of "real" async/await is not something I would consider beneficial in most languages. Rust is a language that is all about low level details and performance, so it actually makes sense there, but that's a rare exception, in my opinion. Developers generally shouldn't need to worry about things a good runtime can take care of, just like you don't need to worry about when you're going to free an object in C#... the runtime takes care of these details that are rarely relevant to meeting the developer's objectives. When you absolutely need that control, there are usually escape hatches. If the application you're writing frequently requires unlimited control, you should probably be using an unmanaged language like Rust to begin with. [0]: https://pkg.go.dev/runtime#LockOSThread https://pkg.go.dev/runtime#LockOSThread
- jayd16 5y ago>This is an exceptionally low level detail that very few people should ever have to think about. Every popular UI package uses a UI thread pattern. Every UI dev thinks about this.
- coder543 5y agoThis should be handled transparently by the library, not the application developer. Which is not to say that UI frameworks developed decades ago got this right. As I said, Go handles this problem just fine, apparently disproving your original argument, which was the main point. Async/await with explicit yield points isn’t needed to support this pattern.
- VincentEvans 5y agoI wish for just one thing: native AOP (aspect oriented programming) aka Python-style decorators and context managers. Everything else I need C# already covers adequately.
- tester756 5y agoYou mean Java's "Annotation Oriented Programming"? like @Transactional? If yes, then I'd really do not want those "magic-like, tricky when it comes to debugging" features
- VincentEvans 5y agoLast time I used Java, it looked to me that AOP is supported with compile-time byte-code rewriting, which might explain why it may feel like magic and be hard to debug. .Net also has a IL-rewriting 3rd party toolkits that enable AOP, namely Postsharp - but my experience with it wasn’t great for similar reasons you stated. Maybe I did something incorrectly, but my impression of tools that generate code at compile time - is that you can’t step through the resulting code. Python on the other hand is both flexible and simple. The decorator code simply wraps the function it decorates (you get a lambda variable that will contain the function you annotate, so you do whatever it is you need to do, and then call the original function. Or not, your choice. ) and doesn’t feel complicated at all. Debugging is simple. Try it and you might change your mind - perhaps C# designers could use a similar source of inspiration.
- giaour 5y ago> aka Python-style decorators and context managers Genuinely curious: aren't Python decorators basically the same as C# annotations, and aren't context managers covering the same ground as a C# using statement?
- VincentEvans 5y agoBased on my experience with C# annotations they require cooperation of the function being annotated or the code that calls it. There has to be code somewhere that checks if an annotation of expected type is present, reads its attributes and possibly executes it, and then proceeds based on results. Python decorators are basically true proxies. The code being decorated or the code that calls it - does not need to be aware in any way of the decorator’s presence, and the decorator gets inserted into the call stack and has access to all call parameters, including the lambda of the decorated function. Regarding context managers I would need to come back to this post, as I don’t think IDisposable is capable of solving the same use cases, but it’s not on top of my mind as to why.
- keithnz 5y agothey are working on DUs, but I think it is a bit stalled as it gets a bit odd with their enum syntax, but you can actually do them reasonably simply right now. I have a stack overflow answer here (and a link to a F# example I rewrote using C#) https://stackoverflow.com/questions/63724308/using-c-sharp-9-0-records-to-build-smart-enum-like-discriminated-union-like-sum/66325818#66325818 https://stackoverflow.com/questions/63724308/using-c-sharp-9... The only thing is you don't get exhaustive type checking, now depending on how passionate you are, that can be a must have, but I actually don't mind without. One of the big lacking things for me is the lack of being able to make types from basic types, sort of like a typedef in C++. F# allows you to do it, but it actually fakes it as .NET itself has no concept of this. This is a PITA if you want types for things like CustomerId which is just an int, but you want it such that CustomerId is typed and can't be passed to other places that would take an int, only if places that take that type. You can model it with a record, but it becomes a bit unnatural and makes mapping it to datastores more effort. There's a few more things I think they could steal from F# - a way to do pipe operators - Type providers like https://fsprojects.github.io/FSharp.Data/ https://fsprojects.github.io/FSharp.Data/ - computation expressions (monads without the drama)
- throw868788 5y agoI do think the pipe operator is very tied into the first-class currying support and HM type inference in F#. In C# I think it makes a lot less sense. To be honest I think each language should play to their strengths and only "steal" things that benefit their current market of users and how they work. If it augments them that's fine. Otherwise you risk cluttering the language with too many ways to do things. If you want all these F# features you probably just want F# - its not too hard to call `dotnet new classlib -lang F#` these days and mix both in together in a solution. Having worked in a few C++ shops, at least from my experience, it can result in a lot of useless debates and internal wars if you keep on adding different features from different paradigms into the language whilst trying to keep backwards compatibility. My view is that if you want unions/non-nullability/data vs classes even if C# gives you the features, it feels more natural to code that way in F# due to the environment around the features and years of optimising that code path. It's just less noisy and less workaround'y. i.e. each language typically prioritizes enhancements and features based on what users in that language are having pain points on. In that sense F# is much further on the data/function paradigm than C# is - conversely when doing low level stuff C# is often in front having to cater for that for some time.
- soupshield 5y agoWe have extension methods; I would like extension properties.
- hackerfromthefu 5y agoI agree this could have compelling uses.
- VikingCoder 5y agoNot C# itself, but I'd love to see XNA come back, or Monogame get support from Microsoft, or something.
- pjmlp 5y agoMonogame has some support from Microsoft, https://dotnet.microsoft.com/en-us/apps/games/ecosystem https://dotnet.microsoft.com/en-us/apps/games/ecosystem But the problem is the WinDev silo, they are pretty much against anything not C++/COM. XNA died because when Phil Spencer left, no one else cared and naturally XNA got rewritten in C++ as DirectXTK.
- tonyedgecombe 5y agoMore about .Net than C# but a consistent story on UI code, something I could expect to rely on for the next ten or twenty years.