News for hackers. Stuff that matters.

neonsunset

Re:So, you want to chunk really fast? on Monday January 05, 2026 @02:33PM (#46503579)
.NET's string.Split implementation is very close to what the article showcases, even 3-character limit is there: https://github.com/dotnet/runtime/blob/main/src/libraries/Sy...
Re:Fucking Approachable Swift Concurrency on Tuesday December 30, 2025 @10:58AM (#46434606)
C# :)

    async Task<User> FetchUser(int id, HttpClient http, CancellationToken token)
    {
        var addr = $"https://api.example.com/users/{id}";
        var user = await http.GetFromJsonAsync<User>(addr, token);
        return user ?? throw new Exception("User not found");
    }
Just don't ship to PlayStation and discourage others until Sony changes (is forced to) policy.
Re:Go-boot: bare metal Go UEFI boot manager on Wednesday December 24, 2025 @10:13PM (#46381751)
I saw the email, and thanks. This is okay - I did not exercise (nor anyone should) good impulse control when dealing with bad faith arguments, which inevitably led to an account ban. Either way, Merry Christas!
Re:Go-boot: bare metal Go UEFI boot manager on Wednesday December 24, 2025 @06:44PM (#46380559)
What? NRTs are used everywhere with WarningAsErrors:nullable also gaining popularity. Whatever environment you are dealing with C# in, if it’s the opposite I suggest getting away from that ASAP.
Re:Rue: Higher level than Rust, lower level than Go on Sunday December 21, 2025 @09:56PM (#46350855)
FWIW JIT is rarely an issue, and enables strong optimizations not available in AOT (it has its own, but JIT is overall much better for throughput). RyuJIT can do the same speculative optimizations OpenJDK Hotspot does except the language has fewer abstractions which are cheaper and access to low-level programming which allows it to have much different performance profile.

NativeAOT's primary goal is reducing memory footprint, binary size, making "run many methods once or rarely" much faster (CLI and GUI applications, serverless functions) and also shipping to targets where JIT is not allowed or undesirable. It can also be used to ship native dynamically or statically (the latter is tricky) linked libraries.

Re:Memory Safety in C# vs. Rust on Tuesday December 16, 2025 @12:42PM (#46291579)
C# actually already has limited lifetime analysis :)

https://em-tg.github.io/csborrow/

> Ownership model for example, would it be possible to enforce practice via some-sort of meta framework?

It should be possible to at least write an analyzer which will be based on IDisposable-ness of types to drive this. Notably, it is not always more efficient to malloc and free versus using GC, and generational moving GCs do not operate on "single" objects allocating and freeing them, no, so you cannot "free" memory either (and it's a good thing - collection is marking of live objects and everything unused can be reclaimed in a single step).

Also the underlying type system and what bytecode allows is quite a bit more powerful than what C# makes use of, so a third language targeting .NET could also yield a better performance baseline by better utilizing existing (very powerful) runtime implementation.

Lastly, there have been many improvements around devirt and object escape analysis, and GC changes are also a moving target (thanks to Satori GC), so .NET is in quite a good spot and many historical problems were or are in the process of being solved, that make Rust-style memory management less necessary (given in Rust you also make use of it because you want to be able to run your code on bare metal or without GC at all, only relying on host-provided allocator - if you do not have such requirement, you have plenty of more convenient options).

Try that on ARM64 and the result will be the opposite :)

On M4 Max, Go takes 0.982s to run while C# (non-SIMD) and F# are ~0.51s. Changing it to be closer to Go makes the performance worse in a similar manner.

> Go fastest language with own compiler (ie not dependent to GCC/LLVM).

C# is using CoreCLR/NativeAOT. Which does not use GCC or LLVM also. Its compiler is more capable than that of Go.

Re:Reinventing how .NET builds and ships (again) on Tuesday November 25, 2025 @10:16PM (#46053845)
Note how practitioners of .NET praise it and non-practitioners (users of .NET Framework) criticize it.
Re:.NET 10 on Wednesday November 12, 2025 @06:40AM (#45898943)
It is as simple as what you get with Cargo, and possibly even more readable.

.NET, unlike Go, has all needed management commands built into its CLI too: dotnet new {template}, dotnet add/remove package, dotnet sln add/remove, etc.

Re:The state of SIMD in Rust in 2025 on Thursday November 06, 2025 @06:00AM (#45833815)
It is atypical for otherwise mainly high-level languages to have this. Moreover, C# and F# get this through completely independent work runtime libraries and RyuJIT, not by being lazy and having LLVM do everything which is also why Go and Java are so so far behind in this area.
Re:The state of SIMD in Rust in 2025 on Wednesday November 05, 2025 @04:33PM (#45828337)
You are not "forced" into unsafe APIs with Vector<T>/Vector128/256/512<T>. While it is a nice improvement and helps with achieving completely optimal compiler output, you can use it without unsafe. For example, ZLinq even offers .AsVectorizable LINQ-style API, where you pass lambdas which handle vectors and scalars separately. It the user code cannot go out of bounds and the resulting logic even goes through (inlined later by JIT) delegates, yet still offers a massive speed-up (https://github.com/Cysharp/ZLinq?tab=readme-ov-file#vectoriz...).

Another example, note how these implementations, one in unsafe C# and another in safe F# have almost identical performance: https://benchmarksgame-team.pages.debian.net/benchmarksgame/..., https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

Re:Safe zero-copy operations in C# on Tuesday September 30, 2025 @10:45AM (#45426139)
No, slices in Go are more akin to ArraySegment but with resizing/copy-on-append. It does not have the same `byref` mechanism .NET supports, which can reference arbitrary memory (GC-owned or otherwise) in a unified way as a single (special) pointer type.
In C# nothing stops you from doing `var t = Task.Run(() => ExpensiveButSynchronous());` and then `await`ing it later. Not that uncommon for firing off known long operations to have some other threadpool thread deal with it.

Unless you literally mean awaiting non-awaitable type which...just doesn't make sense in any statically typed language?

Don't bother: https://news.ycombinator.com/item?id=43396171

These people could not care less about engaging with the subject, they are here because they feel obliged to engage in a moment of hatred of what they think is an enemy tribe.

We've had this conversation before, it's likely a waste to reply but, well, my mistake.

For those interested as to why: https://news.ycombinator.com/item?id=43396171

A few more arguments while we're at it:

https://dotnet.microsoft.com/en-us/platform/telemetry (Linux leads with 77% of all systems invoking .NET CLI commands)

https://github.com/dotnet/runtime/blob/main/src/libraries/Sy... (first-class epoll/kqueue integration with async, much like the one Go has with goroutines via netpoll)

https://github.com/dotnet/runtime/blob/main/src/coreclr/gc/u... (GC implementation is cgroups-aware, unlike Go)

using var stream = GetStream(); does not introduce new (lexical) scope, avoiding use means that the type system either has to understand move semantics (in case the stream is returned or move elsewhere, but then, what about sharing?) or have full-blown borrow checker which will emit drop.
Wait, what? The => operator is just for lambdas, short-form returns and switch expression arms, which is as common as it gets!

Have you never worked with any other language which lets you do these?

    var say = (string s) => Console.WriteLine(s);
or

    struct Lease(DateTime expiration)
    {
        public bool HasExpired => expiration < DateTime.UtcNow;
    }
or

    var num = obj switch
    {
        "hello" => 42,
        1337 => 41,
        Lease { HasExpired: false } => 100,
        _ => 0
    };
You'll see forms of it in practically every (good) modern language. How on Earth is it confusing?

Authentication is generally a difficult subject, it is a weaker(-ish) aspect of (otherwise top of the line) ASP.NET Core. But it has exactly zero to do with C#.

Hey, in F# you replace 'let' bindings with 'use' for disposable types!
> parts of the more modern C# is also a confusing mess

Do you have any examples?

Re:New high-quality hash measures 71GB/s on M4 on Saturday May 17, 2025 @10:01AM (#44014398)
Same here. And I’m not aware of quality issues with GxHash either. For large(r) inputs I’d expect it to be easily competitive. And it’s better than XXH3 on my M4.
Re:New high-quality hash measures 71GB/s on M4 on Friday May 16, 2025 @11:57PM (#44011932)
If whatever you are doing is heavy on hashmap lookups (and you are ok with not rewriting into something more bespoke+complicated) - the faster hash function and the cheaper baseline cost of calling it - the better (i.e. XXH3 can have disadvantages, with its popular impl. for dispatching to the necessary routine).

This looks like an interesting potential alternative to GxHash. GxHash is nice but sadly I found AES intrinsics to have somewhat high latency on AMD's Zen 2/3 cores, making it a loss on short strings (but until I measured it on our server hw, M4 Max sure had me fooled, it has way better latency despite retiring more AES operations!).

Let's revisit past conversations:

- https://news.ycombinator.com/item?id=43226624

- https://news.ycombinator.com/item?id=43584056

- https://news.ycombinator.com/item?id=36736326

And more. I'm not sure what you found in (checked) exceptions. If you'd like explicit error handling, we have holy grail in the form of Rust which beautifully solves it with implicit returns, error type conversions and disambiguation between error and panic model. I'd prefer to use that one as it actually reduces boilerplate and improves correctness, the opposite to the outcome of using checked exceptions.

Quite a few languages "loved" by "Linux communities" tend to have rather rudimentary integration with Linux kernel's facilities or worse packaging story.

For example, Go does not understand cgroups limits and needs an external package to solve this. .NET can read and accommodate those natively. It also ships with excellent epoll-based socket engine implementation. It's on par with Go (although I'm not sure which one is better, but .NET performs really well on high-throughput workloads).

Most of the features that require Apache or community packages in Java ship out of box in .NET (or via extension packages).

They also tend to be of higher quality and provide better performance.

IIRC all previous conversations about checked exceptions here ended up with the swift conclusion that they are heavily discouraged throughout Java code.
I suppose the difference of opinion comes down to whether you consider hiding side effects a good or a bad thing. And whether you want to have easy composition and cancellation (Go struggles with passing context around a lot, in .NET it's much less of an issue if at all, depending on codebase).

If you don't want to join on some other virtual thread or goroutine completing immediately (and with Goroutines it's additionally painful since you need to communicate completion separately), it's more difficult and costlier than doing so with tasks/futures.

Usually dual APIs are offered when they do distinctly different things. Async calls on Socket go through epoll/kqueue via SocketAsyncEngine, which has observably different behavior to regular sockets. There is no such duality in high-level APIs like HttpClient's `.GetStringAsync`.

You are not free from having to worry about it with virtual threads either. If you block a carrier thread with such a low-level API call, the runtime will have a bad time. Or you will always end up paying for a context switch (if you maintain a separate pool of block-able threads).

Green threading UX is better for "regular" code that never bothers to take advantage of concurrency features, but if you do want them, you are quickly back to usually more ceremonious structured concurrency abstractions which, lo and behold, can reimplement the same task system with a worker pool but on top of virtual threads.

If you start to care about cancellation, suddenly you are back to coloring problem regardless. I agree with you that having to write many await's in quick succession is tiresome and unnecessary. It's partially a fault of library authors who name methods "GetSomeLongNameAsync" instead of "Get" or "Query". But other than this it's not as invasive as people make it out to be, and encourages writing highly concurrent code - reducing latency 2x can require moving one or two awaits around. Not so much in Java/Erlang/Go.

In the end, .NET is going hybrid route. Circa .NET 10/11 Roslyn will stop emitting state machines and something state-machine-like will be produced by the compiler itself iff the asynchronous execution suspends, and will be otherwise practically free.

https://github.com/dotnet/runtime/blob/main/docs/design/spec...

Mind you, short-lived operations are much cheaper with stackless co-routine model like in C#/F# or Rust than spawning an entire, even if virtual, thread/process.

Older »