That being said, because there's no one perfect language, it's handy to have a few in your arsenal. As much as I like C#, I'd still reach for Python for any data or ML type use cases.
That being said, because there's no one perfect language, it's handy to have a few in your arsenal. As much as I like C#, I'd still reach for Python for any data or ML type use cases.
But it has felt like the FOSS library ecosystem for .NET is not quite as good as it is for Rust. C# is far older than Rust, and NuGet apparently has 3.5x as many packages as crates.io has crates. Despite that, my experience has been that I'm more likely to find a good Rust library for any random thing I want to do. Rustdoc documentation isn't amazing but it's consistent, and venturing into other ecosystems usually reminds me that things can be worse.
The downside of C# was microsoft, but maybe thats changed now? I know they made a lot of effort to make the .NET framework more cross platform.
var a = new A();
A a = new();
A a = new A();I haven't written C# in a while, but I don't remember seeing that one. I skimmed the C# grammar and didn't see it there either, but I only glanced and might have missed an entire section.
I'm honestly surprised they haven't add the ability to drop the `new` keyword like Kotlin:
val a = A();Go is the only language that gets concurrency right.
Rust async is ugly but it’s ugly because async is ugly and as a systems language there are limits to how much of that ugliness it can hide.
If we could fix threads to scale better at the OS or core library level we’d save insane amounts of developer time.
- ad hoc callbacks, which had a great Result-ish type signature but really do warrant the “hell” in “callback hell”
- Promise APIs, which are semantically equivalent to async the keyword, unless you care about call stacks, and have a lot of the same hellish problems as the ad hoc callbacks they were meant to address (less nesting! same everything else!)
- Um fibers? Good luck making sense out of whatever that’s doing. It’s a good idea, but it’s also all opaque magic when you try using it.
- Actual threads and child processes… there are valid use cases, and they’re worth pursuing if you have a valid use case, but the facilities for development with them are basically “here’s a bunch of low level concepts that closely mirror their system level counterparts, hope you know/figure out what you’re doing!”
The author of esbuild gave up trying to code esbuild with nodejs/worker threads and switched to Go for a less limited/restricted concurrency environment.
Okay with that clarification I can agree it’s a good model, given its constraints. The event loop with async IO in the abstract is a good way to model a single process/thread workload for many use cases that fit it.
> I'm not sure if this abstraction is better than all of the available alternatives if you compare it to high-level features multi-threaded runtimes offer like thread-safe collections, atomic updates, concurrent hash maps, immutability, structured concurrency, etc... as in Java/Clojure.
Clojure’s solution to concurrency is a breath of fresh air, regardless of your execution environment, because its state transactional semantics are great whether your concurrency is in one process/thread or spread across many. I can’t speak to typical Java solutions, but my general sense is they’re higher level and more powerful than Node’s for actually crossing process/thread boundaries, but subject to most of the shared state problems Java has even in a single process/thread.
> The author of esbuild gave up trying to code esbuild with nodejs/worker threads and switched to Go for a less limited/restricted concurrency environment.
After a lot of exploration of Node worker threads, I’d probably similarly look elsewhere if I had a workload suited to it. You can do a lot with Node worker threads with a lot of special tuning for a use case, and I even have some proof of concept code demonstrating that it can be much better than common usage. But I put it on hold because the complexity of making it perform well is very high compared to optimizing the single thread default.
Lol. I guess you haven't seen Elixir.
When you couple this with a (mostly) bunch of noob devs who have been told Go is super safe because of it's type safety, you have a recipe for disaster.
The combination of language features and surrounding social effects means, once you pursue concurrency, Go abruptly becomes one of the most dangerous languages to use for any industry where subtle errors of value are a problem ... like anything to do with money.
p.s. No slight intended to Elixir, it avoids all these risks.
Java and Elixir both have taken the non-async approach. C# is actively looking into it as well now too: https://twitter.com/davidfowl/status/1532880744732758018
Another issue is that Microsoft 's first party libraries are now increasingly designed to funnel you into Azure services. The language is great, but the ecosystem is rotten.
It actually helps a lot that everything's so open source, because often companies will spit out a SDK for .NET to check a box and not have good docs around it because most of their customers aren't using .NET except for a few enterprise whales.
> Microsoft 's first party libraries are now increasingly designed to funnel you into Azure services.
Outside of the solution for scaling Blazor being "Azure SignalIR service" I'm having trouble with this one too. Their docs often call out Azure, but there's not a ton of bias in support (again, totally might just be that I don't get in the weeds enough).
https://learn.microsoft.com/en-us/aspnet/core/security/authe...
It would be odd if they only gave like Cognito as an example (especially considering AAD is free). And I didn’t know people really used IdentityServer as much in new apps, there’s other ways to do that.
Which new features do you dislike?