<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hacker News: burntsushi</title><link>https://news.ycombinator.com/user?id=burntsushi</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Sun, 12 Apr 2026 16:12:13 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=burntsushi" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by burntsushi in "RE#: how we built the fastest regex engine in F#"]]></title><description><![CDATA[
<p>> for simple string literals it will definitely lose to Hyperscan and Rust regex since they have a high effort left-to-right SIMD algorithm that we cannot easily use<p>I think "simple string literals" undersells it. I think that description works for engines like RE2 or Go's regex engine, but not Hyperscan or Rust regex. (And I would put Hyperscan in another category than even Rust regex.) Granted, it is arguably difficult to be succinct here since it's a heuristic with difficult-to-predict failure points. But something like: "patterns from which a small number of string literals can be extracted."</p>
]]></description><pubDate>Wed, 04 Mar 2026 13:57:12 +0000</pubDate><link>https://news.ycombinator.com/item?id=47247447</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=47247447</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47247447</guid></item><item><title><![CDATA[New comment by burntsushi in "Date is out, Temporal is in"]]></title><description><![CDATA[
<p>"niche" doesn't mean "unimportant." It just means "uncommon." It's a relative term.<p>The vast vast majority of people using general purpose datetime libraries are not in need of GPS handling or high precision scientific calculations.</p>
]]></description><pubDate>Tue, 13 Jan 2026 15:12:06 +0000</pubDate><link>https://news.ycombinator.com/item?id=46602023</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46602023</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46602023</guid></item><item><title><![CDATA[New comment by burntsushi in "Date is out, Temporal is in"]]></title><description><![CDATA[
<p>Why should they though? To me it seems like a niche of a niche. I think there is plenty of room for scientific datetime libraries to service this need in a way that is likely better than what a general purpose datetime library would provide. (And indeed, there are many of them.)<p>I say this as someone who had leap second support working in a pre-release version of Jiff[1] (including reading from leapsecond tzdb data) but ripped it out for reasons.[2]<p>[1]: <a href="https://github.com/BurntSushi/jiff" rel="nofollow">https://github.com/BurntSushi/jiff</a><p>[2]: <a href="https://github.com/BurntSushi/jiff/issues/7" rel="nofollow">https://github.com/BurntSushi/jiff/issues/7</a></p>
]]></description><pubDate>Mon, 12 Jan 2026 20:05:29 +0000</pubDate><link>https://news.ycombinator.com/item?id=46593491</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46593491</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46593491</guid></item><item><title><![CDATA[New comment by burntsushi in "Date is out, Temporal is in"]]></title><description><![CDATA[
<p>> but the datetime APIs refuse to expose leap-second info because they're too committed to "only UTC is in-scope for this project".<p>This doesn't make sense on at least two different levels.<p>First, pedantically, the definition of UTC <i>as a time scale</i> is that it includes leap seconds. So if you're committed to UTC, then you're supporting leap seconds.<p>Second, and to more broadly address your point, you should say, "they're too committed to 'only the POSIX time scale is in-scope for this project.'" That more accurately captures the status quo and also intimates the problem: aside from specialty applications, basically everything is built on POSIX time, which specifically ignores the existence of leap seconds.</p>
]]></description><pubDate>Mon, 12 Jan 2026 19:40:57 +0000</pubDate><link>https://news.ycombinator.com/item?id=46593183</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46593183</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46593183</guid></item><item><title><![CDATA[New comment by burntsushi in "Opus 4.5 is not the normal AI agent experience that I have had thus far"]]></title><description><![CDATA[
<p>Nice. Yeah I'd have to actually look at what it did. For the task of substring search, it's extremely easy to fall into a local optima. The `memchr` crate has oodles of benchmarks, and some of them are very much in tension with others. It's easy to do well on one to the expense of others.<p>But still, very neat.</p>
]]></description><pubDate>Tue, 06 Jan 2026 22:09:00 +0000</pubDate><link>https://news.ycombinator.com/item?id=46519543</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46519543</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46519543</guid></item><item><title><![CDATA[New comment by burntsushi in "Opus 4.5 is not the normal AI agent experience that I have had thus far"]]></title><description><![CDATA[
<p>> How about porting BurntSushi's absurdly great Rust optimized string search routines to C and making them faster?<p>How did it do? :-)</p>
]]></description><pubDate>Tue, 06 Jan 2026 21:44:41 +0000</pubDate><link>https://news.ycombinator.com/item?id=46519306</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46519306</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46519306</guid></item><item><title><![CDATA[New comment by burntsushi in "C Is Best (2025)"]]></title><description><![CDATA[
<p>> With C you may, if you wish, develop a big sensibility to race conditions, and stay alert. In general it is possible that C programmers have their "bugs antenna" a bit more developed than other folks.<p>I suppose it's possible. I wonder if I'll become a better driver if I take off my seatbelt. Or even better, if I take my son out of my car seat and just let him roam free in the back seat. I'm sure my wife will buy this.<p>In all seriousness, your comment reminds me of this funny video: <a href="https://www.youtube.com/watch?v=glmcMeTVIIQ" rel="nofollow">https://www.youtube.com/watch?v=glmcMeTVIIQ</a><p>It's nowhere near a perfect analogy, but there are some striking similarities.</p>
]]></description><pubDate>Tue, 06 Jan 2026 15:50:36 +0000</pubDate><link>https://news.ycombinator.com/item?id=46513832</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46513832</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46513832</guid></item><item><title><![CDATA[New comment by burntsushi in "C Is Best (2025)"]]></title><description><![CDATA[
<p>Not necessarily at all. Go peruse the `regex` crate source code, including its dependencies.<p>The biggest `unsafe` sections are probably for SIMD accelerated search. There's no "unnatural abstractions" there. Just a memmem-like interface.<p>There's some `unsafe` for eliding bounds checks in the main DFA search loops. No unnatural abstractions there either.<p>There's also some `unsafe` for some synchronization primitives for managing mutable scratch space to use during a search. A C library (e.g., PCRE2) makes the caller handle this. The `regex` crate does it for you. But not for unnatural reasons. To make using regexes simpler. There are lower level APIs that provide the control of C if you need it.<p>That's pretty much it. All told, this is a teeny tiny fraction of the code in the `regex` crate (and all of its dependencies).<p>Finally, a demonstration of C-like speed: <a href="https://github.com/BurntSushi/rebar?tab=readme-ov-file#summary-of-search-time-benchmarks" rel="nofollow">https://github.com/BurntSushi/rebar?tab=readme-ov-file#summa...</a><p>> Is is a tradeoff, not a silver bullet.<p>Uncontroversial.</p>
]]></description><pubDate>Tue, 06 Jan 2026 15:48:01 +0000</pubDate><link>https://news.ycombinator.com/item?id=46513793</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46513793</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46513793</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>> It may just be a matter of perspective -- if you don't count rust pre 1.0, then yeah it "never" involved backtrace.<p>Yes. I'm only counting what has been part of the stable API since Rust 1.0.<p>I agree that following the stabilization path and future direction of a feature can be difficult.<p>> Because if the only purpose was error chains, it could have been in core on the day of rust 1.0, as it is today. I think what actually happened is `fn backtrace(&self) -> Option<Backtrace>` was removed shortly before 1.0, but there were some misgivings about that and some on the core team wanted to bring that back eventually. And that was the main reason that it could not move to core, because that would make it a breaking change to bring `fn backtrace` back. At least that's what I remember from PRs I followed at the time. (There may have been other reasons besides this though?)<p>The only purpose is not chaining. Backtraces were definitely a desirable part of it! But we wanted to move `Error` to `core` and having backtraces be tightly coupled to `Error` would not allow that. As far as I remember, that was always the tension. To my memory, it wasn't until Jane wrote down the "generic member access" direction[1] for the `Error` trait that this tension was finally broken.<p>[1]: <a href="https://github.com/rust-lang/rfcs/pull/2895" rel="nofollow">https://github.com/rust-lang/rfcs/pull/2895</a></p>
]]></description><pubDate>Mon, 29 Dec 2025 14:12:44 +0000</pubDate><link>https://news.ycombinator.com/item?id=46420946</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46420946</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46420946</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>Sure, I've done it too: <a href="https://docs.rs/ignore/latest/ignore/enum.Error.html" rel="nofollow">https://docs.rs/ignore/latest/ignore/enum.Error.html</a><p>It's not necessarily about frequency, but about extensibility. There's lot of grey area there. If you're very certain of your error domain and what kinds of details you want to offer, then the downside of a less extensible error type may never actualize. Similarly, if you're more open to more frequent semver incompatible releases, then the downside also may never actualize.</p>
]]></description><pubDate>Mon, 29 Dec 2025 13:40:50 +0000</pubDate><link>https://news.ycombinator.com/item?id=46420638</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46420638</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46420638</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>That can be tricky because there may be a trade-off between error message quality and something else. Like, perhaps, the size of an error, code size or even runtime performance. Another trade-off with too-detailed errors---especially when those details are part of the library API---is that they become an extensibility hazard. Unless you're extremely certain about the line that divides a specific implementation from the logical domain of errors for a particular operation, you might get that wrong. And changing the implementation in the future might want a change in the error details.<p>This is very hand-wavy, but I think we're talking at a very high level of abstraction here. My main point is to suggest that there is more of a balancing act here than perhaps your words suggest.</p>
]]></description><pubDate>Mon, 29 Dec 2025 13:35:11 +0000</pubDate><link>https://news.ycombinator.com/item?id=46420584</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46420584</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46420584</guid></item><item><title><![CDATA[New comment by burntsushi in "How uv got so fast"]]></title><description><![CDATA[
<p>If something is asking for `&mut [T]`, then yes, it's required that it be initialized. This is a good thing, because a `&mut [T]` permits reading that `T` in safe code, which would be UB if the `T` were uninitialized.<p>It seems like your complaint is more about "more APIs should accept possibly uninitialized data, but they don't." Which is fair, but I don't know how big of a deal it really is. There is for sure desire to make this work with `std::io::Read`, and indeed, there are unstable APIs for that[1].<p>[1]: <a href="https://doc.rust-lang.org/std/io/trait.Read.html#method.read_buf" rel="nofollow">https://doc.rust-lang.org/std/io/trait.Read.html#method.read...</a></p>
]]></description><pubDate>Mon, 29 Dec 2025 13:07:41 +0000</pubDate><link>https://news.ycombinator.com/item?id=46420298</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46420298</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46420298</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>To clarify, I'm on libs-api. I've been on it since the beginning. Stabilizing `std::error::Error` was absolutely the right thing to do. There were oodles of things in Rust 1.0 that weren't stable yet that embedded use cases really wanted. There are still problems here (like I/O traits only being available in `std`). The zeitgeist of the time---and one that I'm glad we had---was to ship a stable foundation on which others could build, even if there were problems.<p>But also, to be clear, `core::error::Error` has been a thing for over a year now.<p>> And the benefit of shipping a janky version of `std::error::Error` however many years ago, almost all of which got deprecated, seems hard to put a finger on.<p>Again, I think you are overstating things here. Two methods were deprecated. One was `Error::description`. The other was `Error::cause`. The latter has a replacement, `Error::source`, which does the same thing. And `Error::description` was mostly duplicative with the `Display` requirement. So in terms of _functionality_, nothing was lost.<p>Shipping in the context of "you'll never be able to make a breaking change" is very difficult. The downside with embedded use cases was known at the time, but the problems with `Error::description` and `Error::cause` were not (as far as I remember). The former was something we did because we knew it could be resolved eventually. But the APIs that are now deprecated were just mistakes. Which happens in API design. At some point, you've got to overcome the fear of getting it wrong and ship something.</p>
]]></description><pubDate>Sun, 28 Dec 2025 22:37:17 +0000</pubDate><link>https://news.ycombinator.com/item?id=46415245</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46415245</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46415245</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>> I do think that `std::error::Error` is mostly pointless. That's a value judgment, and reasonable people can disagree.<p>I took it as a statement of fact. It is a factual matter of whether `std::error::Error` has a point to it or not. And it definitively does. I use the error chain in just about every CLI application I've built. It's not even mostly pointless. It's incredibly useful and it provides an interoperable point for libraries to agree upon a single error interface.<p>And one `Error::provide` is stable, it will be even more useful.<p>> I've tried to argue that, it can create bigger problems then it solves. It's a trait that only exists on platforms with `std`. That itself is pretty nasty and if you care at all about platforms that aren't like that, you're taking on a lot of build complexity. If you really need this why not just make your own `trait HasCause` which is like a subset of `std::error::Error` functionality, and simply doesn't require `std`?<p>The `Error` trait has been in `core` for about a year now. So you don't need any build complexity for it.<p>But you're also talking to someone who <i>does</i> take on the build complexity to make `std::error::Error` trait implementations only available on `std`. (Eventually this complexity will disappear once the MSRV of my library crates is new enough to cover `core::error::Error`.) But... there really isn't that much complexity to it? It's a very common pattern in the ecosystem and I think your words are dramatically overstating the work required here.<p>> 1) Why does it require `Display` and then not use it?<p>Because it defines the contract of what an "error" is. Part of that contract is that some kind of message can be generated. If it didn't require `Display`, then it would have to provide its own means for generating a message. It's not a matter of whether it's "used" or not. It's defining a _promise_.<p>> 2) Displaying it is very simple: `format!("{err}")`. If you want to format the error and it's chain of causes, actually using the `std::error::Error` functionality, the recommended way was to use yet another experimental `error_chain` library. When should we actually do that? When is that appropriate?<p>Who says it was "the recommended way"? I never recommended `error_chain`.<p>Writing the code to format the full chain is nearly trivial. I usually use `anyhow` to do that for me, but I've also written it myself when I'm not using `anyhow`.<p>> Now we have a place where there's two different ways to do the same thing (display an error). Additionally there is controversy and churn around it.<p>Yes, this is a problem. If something appears in the `Display` of your error type, then it shouldn't also appear in your `Error::source`. This is definitely a risk of getting this wrong if you're writing your error type out by hand. If you're using a library like `thiserror`, then it's much less likely.<p>> I understand that there's a bright shiny future that people hope it's headed for, where everything around `std::error::Error` is easy and obvious, and we have powerful flexible expressive ergonomic error handling. I was excited about that like 7 years ago, now I just kinda want to change the channel. I'm glad some people still find some benefit in the small improvements that have occurred over time... and I hope in 8 more years there's more to the story than where we are today.<p>I was very happy with error handling in Rust at 1.0 personally.<p>I think people got burned by the churn of the error library treadmill. But you didn't <i>have</i> to get on that treadmill. I think a lot of people did because they overstate the costs of write-once boiler plate and understate the costs of picking the wrong foundation for errors.</p>
]]></description><pubDate>Sun, 28 Dec 2025 22:28:51 +0000</pubDate><link>https://news.ycombinator.com/item?id=46415174</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46415174</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46415174</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>I doubt epage is suggesting that. And note that in that case, the thing distinguishing the cause is not `std::io::Error`, but `std::io::ErrorKind`. The latter is not the error type, but something that forms a part of the I/O error type.<p>It's very rare that `pub enum Error { ... }` is something I'd put into the public API of a library. epage is absolutely correct that it is an extensibility hazard. But having a sub-ordinate "kind" error enum is totally fine (assuming you mark it `#[non_exhaustive]`).</p>
]]></description><pubDate>Sun, 28 Dec 2025 22:15:31 +0000</pubDate><link>https://news.ycombinator.com/item?id=46415060</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46415060</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46415060</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>Yeah I used the weasel-y "something like" for exactly these reasons. :-)</p>
]]></description><pubDate>Sun, 28 Dec 2025 21:29:44 +0000</pubDate><link>https://news.ycombinator.com/item?id=46414724</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46414724</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46414724</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>I don't see any reason for something like `rootcause` to become foundational. Most errors are a linear chain and that's good enough for most use cases.<p>It's correct to say that `std::error::Error` does not support a tree of errors. But it is <i>incorrect</i> to say what you said: that it's pointless and doesn't allow <i>error accumulation</i>. It's not pointless and it does provide error accumulation. Saying it doesn't is a broad overstatement when what you actually mean is something more precise, narrow and niche.</p>
]]></description><pubDate>Sun, 28 Dec 2025 21:26:16 +0000</pubDate><link>https://news.ycombinator.com/item?id=46414688</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46414688</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46414688</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>> It was `std` only and linked to a concept of backtraces, which made it a non-started for embedded. It just seemed to me that it was a bad idea ever to use it in a library and that it would harm embedded users.<p>It was never linked to backtraces. And if you used `std::error::Error` in a library that you also wanted to support in no-std mode, then you just didn't implement the `std::error::Error` trait when the `std` feature for that library isn't enabled. Nowadays, you can just implement the `core::error::Error` trait unconditionally.<p>As for backtrace functionality, that is on the cusp of being stabilized via a generic interface that allows `core::error::Error` to be defined in `core`: <a href="https://github.com/rust-lang/rust/issues/99301" rel="nofollow">https://github.com/rust-lang/rust/issues/99301</a><p>> and it to this day has no built-in idea of "error accumulation".<p>The `Error` trait has always had this. It started with `Error::cause`. That was deprecated long ago because of an API bug and replaced with `Error::source`.<p>> It just felt like too much churn and each one offered barely any distinction to the previous.<p>I wrote about how to do error handling without libraries literally the day Rust 1.0 was published: <a href="https://burntsushi.net/rust-error-handling/" rel="nofollow">https://burntsushi.net/rust-error-handling/</a><p>That blog did include a recommendation for `failure` at one point, and now `anyhow`, but it's more of a footnote. The blog shows how to do error handling without any dependencies at all. You didn't have to jump on the error library treadmill. (Although I will say that `anyhow` and `thiserror` have been around for a number of years now and shows no signs of going away.)<p>> I don't bother with implementing `std::error::Error`, because it's pointless.<p>It's not. `std::error::Error` is what lets you provide an error chain. And soon it will be what you can extract a backtrace from.<p>> I'm kind of in the downcasting-is-a-code-smell camp anyways.<p>I happily downcast in ripgrep: <a href="https://github.com/BurntSushi/ripgrep/blob/0a88cccd5188074de96f54a4b6b44a63971ac157/crates/core/main.rs#L55-L61" rel="nofollow">https://github.com/BurntSushi/ripgrep/blob/0a88cccd5188074de...</a><p>That also shows the utility of an error chain.</p>
]]></description><pubDate>Sun, 28 Dec 2025 21:09:43 +0000</pubDate><link>https://news.ycombinator.com/item?id=46414535</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46414535</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46414535</guid></item><item><title><![CDATA[New comment by burntsushi in "Rust errors without dependencies"]]></title><description><![CDATA[
<p>I'm on libs-api and I'd personally be on board with something like `thiserror` coming into `std`. But it would need a champion I think.</p>
]]></description><pubDate>Sun, 28 Dec 2025 20:51:34 +0000</pubDate><link>https://news.ycombinator.com/item?id=46414369</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46414369</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46414369</guid></item><item><title><![CDATA[New comment by burntsushi in "How uv got so fast"]]></title><description><![CDATA[
<p>> or you yolo it with reserve+set_len, which is invalid Rust because you didn't properly use MaybeUninit for locations which are only ever written<p>`Vec::spare_capacity_mut`[1] gives you a view into the unused capacity. There's nothing "invalid" about it.<p>[1]: <a href="https://doc.rust-lang.org/std/vec/struct.Vec.html#method.spare_capacity_mut" rel="nofollow">https://doc.rust-lang.org/std/vec/struct.Vec.html#method.spa...</a></p>
]]></description><pubDate>Sat, 27 Dec 2025 14:07:17 +0000</pubDate><link>https://news.ycombinator.com/item?id=46401948</link><dc:creator>burntsushi</dc:creator><comments>https://news.ycombinator.com/item?id=46401948</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46401948</guid></item></channel></rss>