I think the language is really well-designed. It does have a lot of features, but still feels pretty coherent and not overwhelming. LINQ is great. As for what's coming, I'm particularly excited about the non-nullable types in C# 8.0.
I wish it would get low syntactic overhead sum types, similar to Haskell, OCaml and F#. That's the biggest thing I currently miss.
One thing I am disappointed in is going with async/await paradigm instead of supporting green threads. This essay explains why pretty well, and has already been linked on HN a few times: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
In a way C# will use a mixture of green-ish threads/threads already, in that await-ed calls are either scheduled on a thread worker pool (via a TaskScheduler) or executed synchronously ("inline")... Which comes with it's own set of surprises and gotchas.
async Task<bool> DoSomethingElse() {
// [0] do something long-running
}
async Task DoSomething() {
var otherTask = DoSomethingElse();
// [1] do something long-running
var other = await otherTask;
if (other) {
// do yet another thing
}
}
So, when will [1] run? Before [0], concurrently on another pool thread to [0], or after [0]? The answer is: you cannot really know from the information presented. The compiler might decide that DoSomethingElse is to be called synchronously ("inline", attached child tasks), so before [1] will get a chance to run. Or it might decide to run it concurrently, but then the TaskScheduler might decide it's doing enough of concurrent work already (e.g. every thread in the pool is busy) and run [1] before [0].This is usually nothing to be concerned about, until it is. Coming from js' world of async-await where a certain order is guaranteed, I footgunned myself in C#... my real-world DoSomethingElse() essentially was a forever-loop that would only terminate on a CancelationToken (basically a "is this canceled" flag) and the compiler decided it should be executed synchronously for me, so [1] never got a chance to run. The fix was Task.Run(DoSomethingElse) btw, thus explicitly not "inline"-ing the call.
https://docs.microsoft.com/en-us/dotnet/standard/parallel-pr...
For instance, many games for the PS(3|4| Vita) are written with something called the PhyreEngine which is based on .NET and lets you make pro-quality games that are portable across those platforms, the PC, and some other platforms too.
I really like .Net Core, but as with everything, the more you use it, the better you get at it and I must admit that my C# skills have suffered a tiny bit.
Technically C# is unquestionably better, but there is just something to be said about a single general purpose language, and as far as the efficiency and speed goes, Python is fast enough for our usage.
Generally while C# doesn't have the wealth of OSS libs like JS or Java, the depth and quality of what is there is often surprising.
We target netcoreapp2.2 and execute the binary by using the dotnet tool pre-installed in containers but you can also just output a binary that can be executed standalone in your chosen platform.
I was able to set up a build agent for CI in a couple of hours; you really only need the SDK and you don't need to go through painful guesswork about what you need to install or copying targets that only exist in the desktop version of Visual Studio or stuff like that.
Also, you don't need to tangle with various runtimes and their licenses (like Java) because there is only one and Microsoft seem to only be interested in monetising their development tools, operating systems and cloud offerings.
I would not have believed you if you told me 5 years ago that C# development could be this good. I could not possibly imagine targeting another language (with the possible exception of front-end code and perhaps front-end web apps)