HNHacker News
TopNewBestAskShowJobs

raggi

2,842 karma · joined December 24, 2009

submissionscomments
raggi··on Thoughts on Go vs. Rust vs. Zig
I really hate the anti-RAII sentiments and arguments. I remember the Zig community lead going off about RAII before and making claims like "linux would never do this" (https://github.com/torvalds/linux/blob/master/include/linux/...).

There are bad cases of RAII APIs for sure, but it's not all bad. Andrew posted himself a while back about feeling bad for go devs who never get to debug by seeing 0xaa memory segments, and sure I get it, but you can't make over-extended claims about non-initialization when you're implicitly initializing with the magic value, that's a bit of a false equivalence - and sure, maybe you don't always want a zero scrub instead, I'm not sold on Go's mantra of making zero values always be useful, I've seen really bad code come as a result of people doing backflips to try to make that true - a constructor API is a better pattern as soon as there's a challenge, the "rule" only fits when it's easy, don't force it.

Back to RAII though, or what people think of when they hear RAII. Scope based or automatic cleanup is good. I hate working with Go's mutex's in complex programs after spending life in the better world. People make mistakes and people get clever and the outcome is almost always bad in the long run - bugs that "should never get written/shipped" do come up, and it's awful. I think Zig's errdefer is a cool extension on the defer pattern, but defer patterns are strictly worse than scope based automation for key tasks. I do buy an argument that sometimes you want to deviate from scope based controls, and primitives offering both is reasonable, but the default case for a ton of code should be optimized for avoiding human effort and human error.

In the end I feel similarly about allocation. I appreciate Zig trying to push for a different world, and that's an extremely valuable experiment to be doing. I've fought allocation in Go programs (and Java, etc), and had fights with C++ that was "accidentally" churning too much (classic hashmap string spam, hi ninja, hi GN), but I don't feel like the right trade-off anywhere is "always do all the legwork" vs. "never do all the legwork". I wish Rust was closer to the optimal path, and it's decently ergonomic a lot of the time, but when you really want control I sometimes want something more like Zig. When I spend too much time in Zig I get a bit bored of the ceremony too.

I feel like the next innovation we need is some sanity around the real useful value that is global and thread state. Far too much toxic hot air is spilled over these, and there are bad outcomes from mis/overuse, but innovation could spend far more time on _sanely implicit context_ that reduces programmer effort without being excessively hidden, and allowing for local specialization that is easy and obvious. I imagine it looks somewhere between the rust and zig solutions, but I don't know exactly where it should land. It's a horrible set of layer violations that the purists don't like, because we base a lot of ABI decisions on history, but I'd still like to see more work here.

So RAII isn't the big evil monster, and we need to stop talking about RAII, globals, etc, in these ways. We need to evaluate what's good, what's bad, and try out new arrangements maximize good and minimize bad.

raggi··on Tunnl.gg
Periodic reminder that just because Go having an easy to use SSH package made these easy to write, connecting to SSH servers and doing TOFU all the time with the keys is far far less safe than webpki, and this service could be relatively easily mitm'd in key scenarios like people being tricked at conferences. It's not as terrifying as the coffee shop taking payments over SSH, but still, this isn't doing E2EE, it's terminating TLS upstream.

There's no SSHFP record (not that openssh uses it by default, and you'd need DNSSEC to make it actually useful), and no public keys documented anywhere to help people avoid MITM/TOFU events.

I get the UX, but it saddens me to see more SSH products that don't understand the SSH security model.

raggi··on Be Like Clippy
Back when people were still trying to make ASPs happen, clippy removal was a professional service. Having clippy running over RDP would cripple servers otherwise capable of serving a bunch of office users.
raggi··on Same-day upstream Linux support for Snapdragon 8 Elite Gen 5
Docs though?
raggi··on Microsoft Will Preload Windows 11 File Explorer to Fix Bad Performance
explorer.exe is both the shell and the file explorer which is an unfortunate state of affairs.

There's long been an option to make it multi-process, but the cost of that option has increased with every release since 95. If I remember correctly, back in the 95 days that would spawn a new explorer process per window.

These days, probably since tabs or so, when you check this option it spawns exactly one other process, even for many windows. The second process has over 100 threads, the shell process normally spawns around 40 when you open a window, only 20 of which exit immediately when you close the window, the rest stick around for fairly arbitrary periods of time.

Note though about 2/3rds of the threads on my system are rooted in the nvidia driver thunks, I really don't know why so many - is it a side effect of the xaml port?

anyway, no idea what the preloading exactly will be doing, but it does sound like a hack over debt. it'd feel better if there was more process isolation being added to the desktop environment, but you know, it's an old desktop OS, so if one window wants to screw with another window, YOLO! On the flip side making stuff like komorebi is trivial on the platform and there is some nicety to that as long as you trust everything you ever run.

raggi··on Ion: Modern System Shell in Rust
I love how one of the screenshots appears to be using the ion window manager, I guess they're very aware of the name collision :D
raggi··on Show HN: ESPectre – Motion detection based on Wi-Fi spectre analysis
my brain expected the part after `-` to be new speculative execution bugs
raggi··on Futurelock: A subtle risk in async Rust
if you can always move the data that's the sweet spot for async, you just pass it down the stack and nothing matters.

all of the complexity comes in when more than one part of the code is interested in the state at the same time, which is what this thread is about.

raggi··on Futurelock: A subtle risk in async Rust
The language team tends to look at these kinds of challenges and drive them to a root cause, which spins off a tree of work to adjust the core language to support what's required by the higher level pieces, once that work is done then the higher level projects are unblocked (example: RPIT for async drop).

That's not always super visible if you're not following the working groups or in contact with folks working on the stuff. It's entirely fair that they're prioritizing getting work done than explaining low level language challenges to everyone everywhere.

I think you're seeing a lack of data and trying to use that as a justification to fit a story that you like, more than seeing data that is derivative of the story that you like. Of course some people were horribly disrupted by the changes, but language usage also expanded substantially during and since that time, and there are many team members employed by many other organizations, and many independents too.

And there are more docs, anyway:

https://rust-lang.github.io/rust-project-goals/2024h2/async.... https://rust-lang.github.io/rust-project-goals/2025h1/async.... https://rust-lang.github.io/rust-project-goals/2025h2/field-... https://rust-lang.github.io/rust-project-goals/2025h2/evolvi... https://rust-lang.github.io/rust-project-goals/2025h2/goals....

raggi··on Futurelock: A subtle risk in async Rust
yes
raggi··on Futurelock: A subtle risk in async Rust
if you want your actors to be independent computation flows and they're in different coroutines or threads, then you need to arrange that the data source can not modify the data once it arrives at the destination, in order to be safe.

in a single threaded fully cooperative environment you could ensure this by implication of only one coroutine running at a time, removing data races, but retaining logical ones.

if you want to eradicate logical races, or have actual parallel computation, then the source data must be copied into the message, or the content of the message be wrapped in a lock or similar.

in almost all practical scenarios this means the data source copies data into messages.

raggi··on Futurelock: A subtle risk in async Rust
i forget if this part unwinds to the exact same place, but some of this kind of design constraint in tokio stems from the much earlier language capabilities and is prohibitive to adjust without breaking the user ecosystem.

one of the key advertised selling points in some of the other runtimes was specifically around behavior of tasks on drop of their join handles for example, for reasons closely related to this post.

raggi··on Futurelock: A subtle risk in async Rust
_an answer_ is performance - the necessity of creating copyable/copied messages for inter-actor communication everywhere in the program _can be_ expensive.

that said there are a lot of parts of a lot of programs where a fully inlined and shake optimized async state machine isn't so critical.

it's reasonable to want a mix, to use async which can be heavily compiler optimized for performance sensitive paths, and use higher level abstractions like actors, channels, single threaded tasks, etc for less sensitive areas.

raggi··on Futurelock: A subtle risk in async Rust
yes, you can produce similar issues with promise guarded states and so on as well, it's a fairly common issue in async programming, but can be surprising when it's hidden by layers of abstraction / far up/down a call-chain.
raggi··on Futurelock: A subtle risk in async Rust
Those pages are out of date, and AsyncDrop is in progress: https://github.com/rust-lang/rust/issues/126482

I think "practically rudderless" here is fairly misinformed and a little harmful/rude to all the folks doing tons of great work still.

It's a shame there are some stale pages around and so on, but they're not good measures of the state of the project or ecosystem.

The problem of holding objects across async points is also partially implemented in this unstable lint marker which is used by some projects: https://dev-doc.rust-lang.org/unstable-book/language-feature...

You also get a similar effect in multi-threaded runtimes by not arbitrarily making everything in your object model Send and instead designing your architecture so that most things between wake-ups don't become arbitrarily movable references.

These aren't perfect mitigations, but some tools.

raggi··on My Impressions of the MacBook Pro M4
Mine too, and I bought an air in the last generation and I barely use it because I thought the 60hz display would be ok, but I've been living with 120's everywhere for long enough the 60hz is actually horrible to use now. First world problems for sure, but it's enough that I literally don't use the machine.
raggi··on Tailscale Peer Relays
True, the relays currently use http and have a web socket path. The web based ssh client in the admin panel uses this transport.
raggi··on Tailscale Peer Relays
(Tailscalar) I'm very bullish on WebTransport in the future, but, it doesn't solve for NAT traversal. I'm watching keenly as well how Iroh gets on with QAD, relatedly.

If it all comes together this may well become more magic :D

raggi··on A worker fell into a nuclear reactor pool
There is no circulation in hair, hair is dead, and it is produced slowly. Nothing about your commentary passes basic scrutiny.
raggi··on /dev/null is an ACID compliant database
There was quite a different context when it was written 15 years ago, but essentially the same root jokes.
raggi··on /dev/null is an ACID compliant database
It's also horizontally scalable: https://gist.github.com/raggi/560087#file-shardnull
raggi··on Ruby core team takes ownership of RubyGems and Bundler
i can confirm the above. sadly felt a confirmation might actually be helpful because there's some wild stuff around the threads today.
raggi··on Discord hack shows risks of online age checks
> At least the kids are safe.

Are they any safer? Roadblocks rarely stopped me as a kid. These kinds of impediments most often resulted in me strategically moving what I was doing to somewhere out of sight of the gatekeepers, most often resulting in less safety. Where do most kids learn to play with fire in modern society? in very very dangerous places.

raggi··on Notes on switching to Helix from Vim
it's 317 unique crates, some of which are internal

  305 with helix- removed
  258 with gix removed (git stuff in multiple packages from a single upstream group)
  240 with windows api wrappers removed.
  170 if you remove all subprojects (split on -/_ taking first field, then uniq).
what's left?

  fast math and various hashes
  backtrace utils
  various build utils
  some allocators, zero copy facilities, mmap and structures   like lrus
  time and date handling
  character maps / internationalization
  concurrency libraries (futures, runtime, etc)
  cross platform path & directory helpers
  support for general unix platforms, for redox, for linux, for windows
  logging infrastructure
  some compression libraries
  markdown
  various testing helpers
  rope string representation
  shell lexer and utils
  terminal interaction models
  toml
  wasm & wasi
compared to neovim, which is hard to determine because c & cmake toolchains are a bit of a shitshow to figure out, but lets take a look at maybe debian, that says 34 package dependencies downstream. The list is clearly missing a bunch of the toolchain, has limited portability and so on, but certainly shorter at 34 - for a single platform. Note also that neovim bundles several dependencies (e.g. markdown and so on - so they're "hidden" (almost surprising debian hasn't done their usual trick of insisting this isn't hidden))

so where's the rest? well the rest is in the project: tokei says helix contains 132kloc. tokei says neovim contains 984kloc.

so round a little and you get: helix has an order of magnitude more dependencies, but also an order of magnitude less code than neovim.

while I'm sympathetic to concerns around dependency bloat, particularly with an eye to the js ecosystem and supply chain security, it's important to look through the right lens - when the functionality is fairly closely equivalent (there are differences, helix has a lot more modern features, vim has a lot more traditional text manipulation and unixy integration features), and there's an order of magnitude tradeoff in both directions - this is likely demonstration of fairly effective code sharing in helix.

there are important supply chain safety techniques required when using a wide number of disparately owned dependencies. there are also important supply chain safety techniques required when managing a wide number of disparately owned sub-directories of a larger project. there could just as well be a needle in neovims vimscript haystack as there is in helix dependency stack, i can tell you now though, as i'm familiar with almost all of helix dependencies i've put eyes over their code at least once, there's almost certainly been more eyes on helix deps recently than on neovims vimscript - though eye's passing over don't always catch things either of course.

raggi··on Rubygems.org AWS Root Access Event – September 2025
Honestly I think everyone involved here, and I know most of them, needs to step back and grow up. Despite the formal tone, and the potential legal issues at play here, this situation seems to be descending into needless childishness with potential life damaging side effects. All sides are being disrespectful.
raggi··on Fast UDP I/O for Firefox in Rust
> I think you are just agreeing with me?

sure, i mean i have no goal of alignment or misalignment, i'm just trying to provide more insights into what's going on based on my observations of this from having also worked on this udp path.

> Which is my point. They are leaving, by my estimation, 10-20x performance on the floor due to external factors. They might be “fast given that they are bottlenecked by low performance systems”, which is good as their piece is not the bottleneck, but they are not objectively “fast” as the primitives can be configured to solve a substantially similar problem dramatically faster if integrated correctly.

yes, though this basically means we're talking about throwing out chunks of the os, the crypto design, the protocol, and a whole lot of tuning at each layer.

the only vendor in a good position to do this is apple (being the only vendor that owns every involved layer in a single product chain), and they're failing to do so as well.

the alternative is a long old road, where folks make articles like this from time to time, we share our experiences and hope that someone is inspired enough reading it to be sniped into making incremental progress. it'd be truly fantastic if we sniped a group with the vigor and drive that the mptcp folks seem to have, as they've managed to do an unusually broad and deep push across a similar set of layered challenges (though still in progress).

raggi··on Fast UDP I/O for Firefox in Rust
> which seems too high for a system call anyways

spectre & meltdown.

> you get 2 us of processing in addition to a full system call to reach 4 Gb/s

TCP has route binding, UDP does not (connect(2) helps one side, but not both sides).

> “But encryption is slow.” Not that slow.

Encryption _is slow_ for small PDUs, at least the common constructions we're currently using. Everyone's essentially been optimizing for and benchmarking TCP with large frames.

If you hot loop the state as the micro-benchmarks do you can do better, but you still see a very visible cost of state setup that only starts to amortize decently well above 1024 byte payloads. Eradicate a bunch of cache efficiency by removing the tightness of the loop and this amortization boundary shifts quite far to the right, up into tens of kilobytes.

---

All of the above, plus the additional framing overheads come into play. Hell even the OOB data blocks are quite expensive to actually validate, it's not a good API to fix this problem, it's just the API we have shoved over bsd sockets.

And we haven't even gotten to buffer constraints and contention yet, but the default UDP buffer memory available on most systems is woefully inadequate for these use cases today. TCP buffers were scaled over time, but UDP buffers basically never were, they're still conservative values from the late 90s/00s really.

The API we really need for this kind of UDP setup is one where you can do something like fork the fd, connect(2) it with a full route bind, and then fix the RSS/XSS challenges that come from this splitting. After that we need a submission queue API rather than another bsd sockets ioctl style mess (uring, rio, etc). Sadly none of this is portable.

On the crypto side there are KDF approaches which can remove a lot of the state cost involved, it's not popular but some vendors are very taken with PSP for this reason - but PSP becoming more well known or used was largely suppressed by its various rejections in the ietf and in linux. Vendors doing scale tests with it have clear numbers though, under high concurrency you can scale this much better than the common tls or tls like constructions.

raggi··on ML needs a new programming language – Interview with Chris Lattner
I'm on the systems side, and I find some of what Chris and team are doing with Mojo pretty interesting and could be useful to eradicate a bunch of polyglot ffi mess across the board. I can't invest in it or even start discussions around using it until it's actually open.
raggi··on Stripe Launches L1 Blockchain: Tempo
Please forgive my pushback but:

No third party: Almost certainly as a user there are still third parties involved, this isn't (AFAICS and based on other discussions) a user facing chain (edit: correction, they do say the chain is public, but here I really mean user facing value: you aren't minting stablecoins, you have to get them from somewhere). At "envisioned" transaction rates you would in practice not be syncing the chain and interacting with it yourself in any meaningful way.

Settlement: chain settlement is different from financial settlement. Between clearing ends there will still need to be sufficient demonstration of KYC, exchange of some form of actual holdings and so on. Typically the attraction of /to stablecoins is that they're used to perform transactions ahead of movement of actualizable value in target currencies. A possible alternative model is that all invested parties sink actual value into a global sink fund backing the stablecoin that is sufficiently protected to ensure that it does not devalue. In practice organizations almost certainly aren't going to part with wealth on those volumes and will operate secondary private exchange markets and settlement in bulk to escape concerns of short term loss, leverage, inflation and many other dynamics.

raggi··on Stripe Launches L1 Blockchain: Tempo
Can you expand on "easier" and "faster" in easier/faster/better. I understand "better" in terms of transparency, shared standards for integration, and various other properties.

I can less immediately expand "easier" and "faster".

Easier: on chain VMs are far from simple or easy, recovery from mistakes is far more complex. Some other aspects such as the implicit common standard might reduce some amount of need for "green field agreement", and the implicit openness of the protocols avoid some of the traps of "here's a rest api, go", but is this the focus? When you look at a wide variety of the big ticket items in everything that needs doing, is the total set easier? Are there surprises there?

Faster: similar to above, this claim is surprising. There's a lot of by-design overhead to a cryptographic ledger system. Lots of things that can be done to make it wider, to reduce latency and increase throughput, but at a fundamental level core operations such as transaction creation require a lot more processing going into a ledger than into a traditional database, even one at scale. Maybe faster here isn't about system faster, but time to product delivery? If so is that common standards? Are there surprises here too, what were they?

Edit: I see elsewhere in the thread you provide some answers in a slightly different framing. A potentially unfair paraphrase and summary seems to be that this enabled integrations to bypass expensive incumbents and comparatively poor traditional infrastructure. If that's a reasonable approximation my question is this: what if you dropped good sized chunks of the blockchain part that is the main system bottleneck, but kept the rest of the properties (shared micro computation model, shared transaction model, common API standard and protocol, eradication of foot dragging incumbents etc).?

← PreviousPage 5 of 25Next →