<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: estebank</title><link>https://news.ycombinator.com/user?id=estebank</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Wed, 19 Aug 2026 01:53:23 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=estebank" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by estebank in "Parsers don't have to be complicated"]]></title><description><![CDATA[
<p>>> Built-in line and column tracking. Any movement across a newline updates the line number, including a backwards seek. getLine and getColumn are always available and both are one-based, which makes decent error messages nearly free.<p>> That doesn't sound like much, but having hand-written plenty of recursive descent parsers, it's most of what you need for good error messages.<p>In my experience having access to the appropriate place where the parser failed is <i>necessary</i> but wholly insufficient for good diagnostics.</p>
]]></description><pubDate>Fri, 07 Aug 2026 11:21:14 +0000</pubDate><link>https://news.ycombinator.com/item?id=49208711</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=49208711</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49208711</guid></item><item><title><![CDATA[New comment by estebank in "Parsers don't have to be complicated"]]></title><description><![CDATA[
<p>I will provide some context from having done a lot of that work.<p>The Rust grammar is actually quite regular, that's why we have things like the turbofish for type parameters (`binding.method::<Type>()`): it makes the grammar unambiguous (a naïve parser would with a complicated grammar that accepts chained comparisons would have to deal with differentiating between `binding.method < value > ()` and  `binding.method<Type>()`). But that doesn't mean the rustc parser doesn't do the work of supporting some the more complex grammar in order to provide better diagnostics. I like to say that rustc actually knows about meta-Rust, a daughter language that goes crazier in its features. I also joke that rustc isn't done until you can paste code from another language and following the suggestions you end up with valid Rust code without loss of the user's intent.<p>Part of the problem is that the places where incorrect code <i>can</i> fail is in more places than the parser. The chained comparisons example is one that is easy for Rust (as it doesn't support them), so the parser itself can produce a "missing turbofish" suggestion with high certainty, but for truly ambiguous expressions, the errors will happen later, during name resolution ("expected a value and found a type") or when checking the number of arguments. A production compiler needs to account for not only the original error, but also silence every knock-down error too. The simplest strategies are to just stop if at the end of a given stage there are errors (which leads to the "wave of errors" experience of fixing the "last" error leading to a ton of new ones) or fully replacing entire blocks of code that had a parse error with an AST node that acts as a tombstone marking that that later stages need to ignore it. The first option leads to a bad experience, and the latter is insufficient. A recent example of looking at this is <a href="https://github.com/rust-lang/rust/pull/159689" rel="nofollow">https://github.com/rust-lang/rust/pull/159689</a>, where `Arc::new(RwLock::new(HashMap<i32, i64>::default()));` currently produces<p><pre><code>  error[E0423]: expected value, found struct `HashMap`
    --> $DIR/suggest-turbofish-parsed-as-comparisons.rs:11:34
     |
  LL |     let _ = Arc::new(RwLock::new(HashMap<i32, i64>::default()));
     |                                  ^^^^^^^
     |
    --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
    ::: $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
     |
     = note: `HashMap` defined here
  
  error[E0423]: expected value, found builtin type `i32`
    --> $DIR/suggest-turbofish-parsed-as-comparisons.rs:11:42
     |
  LL |     let _ = Arc::new(RwLock::new(HashMap<i32, i64>::default()));
     |                                          ^^^ not a value
  
  error[E0423]: expected value, found builtin type `i64`
    --> $DIR/suggest-turbofish-parsed-as-comparisons.rs:11:47
     |
  LL |     let _ = Arc::new(RwLock::new(HashMap<i32, i64>::default()));
     |                                               ^^^ not a value
  
  error[E0425]: cannot find external crate `default` in the crate root
    --> $DIR/suggest-turbofish-parsed-as-comparisons.rs:11:53
     |
  LL |     let _ = Arc::new(RwLock::new(HashMap<i32, i64>::default()));
     |                                                     ^^^^^^^ not found in the crate root
  
  error[E0061]: this function takes 1 argument but 2 arguments were supplied
    --> $DIR/suggest-turbofish-parsed-as-comparisons.rs:11:22
     |
  LL |     let _ = Arc::new(RwLock::new(HashMap<i32, i64>::default()));
     |                      ^^^^^^^^^^^              --------------- unexpected argument #2 of type `bool`
     |
  note: associated function defined here
    --> $SRC_DIR/std/src/sync/poison/rwlock.rs:LL:COL
  help: remove the extra argument
     |
  LL -     let _ = Arc::new(RwLock::new(HashMap<i32, i64>::default()));
  LL +     let _ = Arc::new(RwLock::new(HashMap<i32));
     |
</code></pre>
This is because the expression is syntactically correct as<p><pre><code>  RwLock::new( HashMap < i32, i64 > ::default() );
  ^^^^^^^^^^^^ ------- - ---^ --- - ----------- ^
  |            |       | |  | |   | |
  |            |       | |  | |   | a function call to `default` in the crate root
  |            |       | |  | |   a more than binop
  |            |       | |  | a value to be compared
  |            |       | |  the separator of the second argument to `RwLock::new()`
  |            |       | a value to be compared
  |            |       a less than binop
  |            a value to be compared
  an associated function call
 </code></pre>
but after that PR it would only be the following, even though the parser <i>hasn't</i> changed:<p><pre><code>  error: can't compare two types
    --> $DIR/suggest-turbofish-parsed-as-comparisons.rs:24:41
     |
  LL |     let _ = Arc::new(RwLock::new(HashMap<i32, i64>::default()));
     |                                         ^        ^ these are parsed as "less than" and "greater than"
     |
  help: you likely intended to write type `HashMap` with type parameters, but type parameters in expression contexts require the use of the "turbofish" `::<>`
     |
  LL |     let _ = Arc::new(RwLock::new(HashMap::<i32, i64>::default()));
     |                                         ++
</code></pre>
I think that there's a lot of work needed in the parser itself to produce good diagnostics. There are other strategies, like performing multiple parses at a given point when you've reached a known bad state (you've seen a flag-post that shouldn't be there, but that is a signal for a handful of other known cases), or fully consuming the rest of a block when an unrecoverable parse occurred (we're half-way through parsing function arguments, but failed? consume the rest of the statement or of the parent block, accounting for sub-scopes). The latter can cause <i>the rest of the file</i> to be consumed, but that's an edge-case that in practice is much better than a deluge of irrelevant errors.<p>Another added complexity is how some easy-to-hit errors occur during <i>lexing</i>, which means the compiler has barely any information about the user's code. Mismatched braces/parens is one of those. rustc tries to provide context by keeping a queue of seen open delimiters to point at, and explicitly checking for their indentation level as a heuristic to detect where the user's intent diverged from the code, but that's overly reliant on the code being sanely formatted (thanks to rustfmt-on-save, that's a good bet for many users). For an example of the things rustc can do even in the lexer, you can look at <a href="https://github.com/rust-lang/rust/pull/160592" rel="nofollow">https://github.com/rust-lang/rust/pull/160592</a>.</p>
]]></description><pubDate>Fri, 07 Aug 2026 10:28:50 +0000</pubDate><link>https://news.ycombinator.com/item?id=49208312</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=49208312</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49208312</guid></item><item><title><![CDATA[New comment by estebank in "JEP 401: Value Objects (Preview) merged to OpenJDK master"]]></title><description><![CDATA[
<p>It's a project years in the making.</p>
]]></description><pubDate>Fri, 31 Jul 2026 06:54:02 +0000</pubDate><link>https://news.ycombinator.com/item?id=49119845</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=49119845</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49119845</guid></item><item><title><![CDATA[New comment by estebank in "Memory safety absolutists"]]></title><description><![CDATA[
<p>The thing that has changed is that there are spaces where security is being taken more seriously, and C's memory unsafety became a deal breaker there. I do think that providing a mechanism to run existing C software that isn't performance sensitive in a way that mitigates its limitations is very worthwhile.<p>I think the "static analysis" and the "runtime checks" approaches are complementary, not in opposition, making any noise around having to choose one or the other moot.</p>
]]></description><pubDate>Sat, 25 Jul 2026 21:31:13 +0000</pubDate><link>https://news.ycombinator.com/item?id=49051809</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=49051809</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49051809</guid></item><item><title><![CDATA[New comment by estebank in "Memory safety absolutists"]]></title><description><![CDATA[
<p>Could you point me at the members of the Rust project doing so? I'd want to have a word with them (I'm a member of t-compiler).</p>
]]></description><pubDate>Sat, 25 Jul 2026 21:24:40 +0000</pubDate><link>https://news.ycombinator.com/item?id=49051745</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=49051745</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49051745</guid></item><item><title><![CDATA[New comment by estebank in "How Our Rust-to-Zig Rewrite Is Going"]]></title><description><![CDATA[
<p>I don't think using an example that includes licensing, plenty of regulations governing drivers, the cars themselves and the built environment, enforcement, and plenty of research on the impact of passive infrastructure to make things safer (bollards, daylighting, raised pedestrian intersections, curbs, traffic lights, etc.) makes the case you seem to be trying to make.</p>
]]></description><pubDate>Fri, 17 Jul 2026 16:58:58 +0000</pubDate><link>https://news.ycombinator.com/item?id=48949567</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48949567</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48949567</guid></item><item><title><![CDATA[New comment by estebank in "How Our Rust-to-Zig Rewrite Is Going"]]></title><description><![CDATA[
<p>There's a material difference on one taking risks for oneself and one taking risks where the brunt of the consequences fall on others.</p>
]]></description><pubDate>Fri, 17 Jul 2026 04:17:46 +0000</pubDate><link>https://news.ycombinator.com/item?id=48943283</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48943283</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48943283</guid></item><item><title><![CDATA[New comment by estebank in "How Our Rust-to-Zig Rewrite Is Going"]]></title><description><![CDATA[
<p>> that just lost his most popular open source project<p>As they state in the article, they started the migration a year and a half ago, something that happened a few weeks back would never come into the decision making process.</p>
]]></description><pubDate>Thu, 16 Jul 2026 16:59:56 +0000</pubDate><link>https://news.ycombinator.com/item?id=48937114</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48937114</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48937114</guid></item><item><title><![CDATA[New comment by estebank in "SQLite should have (Rust-style) editions"]]></title><description><![CDATA[
<p>> Are there any drawbacks to Rust editions?<p>That they can't (yet) be used to influence name resolution, so that they can't be leveraged for std API evolution. Work is being done on that front.<p>Older documentation that people find on the internet might be out of date and claim things that don't work but do on later editions, or vice-versa when trying out something that exists in a new edition in an older one. The mitigation for this is that if something is accepted in one edition but not another it must be taken into account in diagnostics so that the divergence is explained.<p>> Does it make the compiler and other tools larger and more complex for each new edition?<p>With editions 2015, 2018, 2021 and 2024, there are ~120 branches in the compiler for changes in behavior, including for changing diagnostics to be more specific. For comparison, just <i>rendering</i> a type error for if else having different types in its arms checks for 4 different conditions. 120 checks is a drop in the bucket compared to the number of things the compiler already has to check for, and the growth rate is very manageable accruing in the double digits over the course of 4 years.<p>> Are the migration tools always fully automatic, quick to execute, and flawless? Is any manual work, or expertise, required for upgrading in the worst case?<p>> Fully automatic<p>For most code, it is. We spend the time creating migration lints that can change your code as part of your upgrade, and we test those using crater to detect the cases that people are using in public libraries. It is conceivable that a project in a private repo is using a pattern that wasn't detected through that, so an appropriate structured suggestion isn't emitted, but I haven't heard of such a situation.<p>> quick to execute<p>it is as fast as cargo check<p>> flawless<p>If the compiler produces a structured suggestion marked as machine applicable, and I believe all edition suggestions are, our level of confidence on them being the right thing to do to get the users' code to compile with the intended behavior is high. Bugs can happen, but don't recall seeing any "incorrect suggestion" in edition lints.<p>> If I read a blog about Rust, and the blog forgot to mention which edition it uses for its code examples, can that cause any problems? Should I just skip the blog if it is old?<p>Differences between editions are actually quite small. You should be able to pick up The Book from 2015 and still learn the language. There are just things that The Book says don't work that now do, or features that were introduced that it doesn't talk about (<i>both</i> impl Trait and + use<'_> were introduced years later).<p>> If I see an interesting repository that I would like to learn from, but it was written in an old edition that I do not want to learn the rules for, will I have to upgrade the codebase myself before learning from it, or should I just skip it?<p>Just use the old edition or upgrade, either thing will just work. You seem to think that the behavior divergences are bigger than they are, and anything that does diverge should be emitting a diagnostic telling you what code to write instead. These are things like "in a previous edition you had to borrow here, in the next edition you don't".<p>> Are there any Rust projects that stay in an old edition for whatever reasons? How large a proportion of Rust projects that are still downloaded and used, are not on edition 2024? As an example, why are these popular projects still on Rust edition 2021?<p>Yes, there are crates that stay in older editions so that they can be used in projects that are frozen in time, like those that are shipped in some distros. (Edit: "frozen in time" as in "they won't update their toolchain", an earlier edition will always work on later ones due to backwards compat guarantees, the other way around of course can't.) To get a sense for it, serde which is a dependency that's almost inescapable is on 2021 edition and targets Rust 1.56. If a project decides that the impact on the ecosystem is bigger than the benefit of using newer language features, then it makes perfect sense to remain in an older edition.<p><a href="https://lib.rs/stats" rel="nofollow">https://lib.rs/stats</a> sadly doesn't include statistics about the set edition, but it does have the graph at the bottom showing you rustc versions that the ecosystem supports, both for <i>all</i> crates and for the most recently updated. For reference, looking at releases.rs to refresh my memory, 1.31 is the introduction of edition 2018, 1.56 2021 and 1.85 2024. Those corresponds with the jumps in the chart. Note that looking at the chart it only tells you the likelihood of a random crate working on an older toolchain.<p>> How much work is it to upgrade someone else's codebase to a newer edition?<p>Not any more than updating your own codebase (and if you're upgrading someone else's it is because you've taken ownership of that code), which is to say, not much.<p>> Does upgrading a large project require intimate knowledge of that project in the worst case?<p>I can't think of any feature that would require that.<p>> How do Rust editions and macros interact?<p>The compiler has the concept of `Span`s, which is the byte offset pointing at a piece of your code. Every node in the AST has a `Span`, and is subsequently used in every later stage. It's what is used to render the diagnostics. But they also carry "context" information: whether a token comes from a macro expansion. And they also carry edition information. This let's you have a macro defined in one edition and use it in another, and the behavior will be the correct one, regardless of how you mix them.<p>> Does definition of macros or usage of macros make upgrading a Rust edition harder? If yes, how much harder in the worst case? Is upgrading always automatic?<p>The only situation I can think of is if there is a change in the parsing of macro arguments. For example, if Rust edition 20XX started parsing `A | B` as an anonymous enum type, then the macro <i>call</i> for `foo!(A | B)` would likely be parsed differently between editions <20XX and edition 20XX. That would be the kind of work you'd have to do. This has happened before in edition 2024, with expressions: <a href="https://doc.rust-lang.org/reference/macros-by-example.html#metavariables" rel="nofollow">https://doc.rust-lang.org/reference/macros-by-example.html#m...</a>. In 2024 `expr` started not matching on `_` and `const {..}`. What was done then was introducing an `expr_2021` matcher with the prior behavior. When you update your edition to 2024 and apply the suggestions, your macro definitions get updated to use `expr_2021` instead of `expr`.<p><i>From your other comment</i><p>> Reading between the lines, it is as if you consider there to be large problems with Rust editions, but you do not wish to make Rust, Rust editions, nor the programming language concept of editions, look bad.<p>Reading your lines, it is as if you already had the conclusion that editions are bad, and are looking for a confession.<p>> Does upgrading a large project require intimate knowledge of that project in the worst case? How much work is it in the worst case?<p>I can't think of a situation where intimate knowledge of the project is needed.<p>> How do Rust editions and macros interact? Does definition of macros or usage of macros make upgrading a Rust edition harder? If yes, how much harder in the worst case?<p>Answered earlier.</p>
]]></description><pubDate>Thu, 16 Jul 2026 15:52:32 +0000</pubDate><link>https://news.ycombinator.com/item?id=48936220</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48936220</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48936220</guid></item><item><title><![CDATA[New comment by estebank in "Theo de Raadt: "You've been smoking something mind altering" (2007)"]]></title><description><![CDATA[
<p>I think that everyone has the power to be wrong, but to be <i>very</i> wrong with <i>convincing arguments</i>, you <i>must</i> be smart.<p>A smart person can come up with post-hoc rationalizations that hold up under some scrutiny, to the point it is very hard to convince them otherwise. Add to that people who became famous or successful on the back of "being right" on some subject matter, getting used to "being right even in the face of overwhelming push back", and you have a recipe for very smart people being <i>very wrong</i> in very visible/loud ways.</p>
]]></description><pubDate>Sun, 12 Jul 2026 18:26:38 +0000</pubDate><link>https://news.ycombinator.com/item?id=48883286</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48883286</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48883286</guid></item><item><title><![CDATA[New comment by estebank in "Prefer strict tables in SQLite"]]></title><description><![CDATA[
<p><a href="https://github.com/tursodatabase/turso" rel="nofollow">https://github.com/tursodatabase/turso</a></p>
]]></description><pubDate>Sat, 11 Jul 2026 23:21:03 +0000</pubDate><link>https://news.ycombinator.com/item?id=48876780</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48876780</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48876780</guid></item><item><title><![CDATA[New comment by estebank in "Postgres rewritten in Rust, now passing 100% of the Postgres regression tests"]]></title><description><![CDATA[
<p>> And some programmers are so good that some issues are self-explanatory and they write good code to note a thing but don't write a test, because implementing the test is more expensive.<p>You don't write a test (just) to verify that your change fixed the issue, but to ensure it doesn't regress in the future after an unrelated refactor.</p>
]]></description><pubDate>Fri, 10 Jul 2026 00:01:03 +0000</pubDate><link>https://news.ycombinator.com/item?id=48854123</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48854123</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48854123</guid></item><item><title><![CDATA[New comment by estebank in "Multilingual experience linked to delayed aging"]]></title><description><![CDATA[
<p>If anything comedy is an excellent way of learning a language: the use of double and triple entendres helps to quickly get exposed to alternate meanings and misunderstandings of words. Comedy aimed at learners or multilinguals can also help, plenty of anglos who learned Spanish can relate to "feeling pregnant" early on :)</p>
]]></description><pubDate>Mon, 06 Jul 2026 17:24:01 +0000</pubDate><link>https://news.ycombinator.com/item?id=48807750</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48807750</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48807750</guid></item><item><title><![CDATA[New comment by estebank in "Multilingual experience linked to delayed aging"]]></title><description><![CDATA[
<p>Someone who can speak English on top of their mother tongue is already multilingual. Anecdotally, people who live anywhere close to a border in Europe tends to speak at least two languages, often more than two, regardless of class or profession.<p>In Latin America, most countries speak Spanish (with the obvious exception of Brazil and smaller colonies from the other European countries), so the every day pressure to learn another language isn't there and English becomes the "obvious" choice. I don't quite get why you seem to discount English entirely.<p>There's always been a Lingua Franca. It hasn't always been the same one. There will likely always be one.</p>
]]></description><pubDate>Mon, 06 Jul 2026 17:20:59 +0000</pubDate><link>https://news.ycombinator.com/item?id=48807713</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48807713</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48807713</guid></item><item><title><![CDATA[New comment by estebank in "How working with a blind client revealed invisible accessibility gaps"]]></title><description><![CDATA[
<p>You sure come across as calm and collected, looking for a good faith discussion...</p>
]]></description><pubDate>Fri, 03 Jul 2026 19:53:29 +0000</pubDate><link>https://news.ycombinator.com/item?id=48779216</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48779216</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48779216</guid></item><item><title><![CDATA[New comment by estebank in "How working with a blind client revealed invisible accessibility gaps"]]></title><description><![CDATA[
<p>In cycling threads you always have comments both telling cyclists to stay out of sidewalks <i>and</i> others telling cyclists that they "only* belong in sidewalks (and away from the road they drive in).<p>It is legal in some places, illegal in as many others, and has caveats almost everywhere (children are almost always allowed, in other places it is based on speed, etc.).</p>
]]></description><pubDate>Fri, 03 Jul 2026 16:11:28 +0000</pubDate><link>https://news.ycombinator.com/item?id=48776702</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48776702</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48776702</guid></item><item><title><![CDATA[New comment by estebank in "How working with a blind client revealed invisible accessibility gaps"]]></title><description><![CDATA[
<p>We can't individual responsibility our way out of systemic problems. Cyclists on sidewalks generally signals terrible bike infrastructure.<p>There are people on bikes that ride like an asshole. There are people on cars that drive like an asshole. Both cause (different levels of) risk for pedestrians. There's only so much we can do about assholes, social ostracism works only so far and social change is much harder to accomplish than modifying our built environment to reduce or eliminate conflict points.<p>As an aside, I've noticed people get startled when I'm on my bike stopped but balancing on my bike while I wait for then to cross. I think some people intuitively model bikes on the same category as cars, so being anywhere close causes them to react as if a car hard crept close.</p>
]]></description><pubDate>Fri, 03 Jul 2026 16:08:48 +0000</pubDate><link>https://news.ycombinator.com/item?id=48776677</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48776677</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48776677</guid></item><item><title><![CDATA[New comment by estebank in "Since Linux 6.9, LUKS suspend stopped wiping disk-encryption keys from memory"]]></title><description><![CDATA[
<p>Yes, that would be one way of doing it. You can model off of the Typed Builder pattern:<p><pre><code>  struct Builder<const A: bool, const B: bool> {
    a: Option<u32>,
    b: Option<u32>,
  }
  struct Val {
    a: u32,
    b: u32,
  }
  impl<const B: bool> Builder<false, B> {
    fn set_a(self, a: u32) -> Builder<true, B> {
      Builder {
        a: Some(a),
        b: self.b,
      }
    }
  }
  impl<const A: bool> Builder<A, false> {
    fn set_b(self, b: u32) -> Builder<A, true> {
      Builder {
        a: self.a,
        b: Some(b),
      }
    }
  }
  impl Builder<true, true> {
    fn build(self) -> Val {
      Val {
        a: self.a.unwrap(),
        b: self.b.unwrap(),
      }
    }
  }
</code></pre>
This won't work for <i>everything</i>, but it is a pattern that I find useful to ensure that things <i>can't</i> happen out of order.</p>
]]></description><pubDate>Thu, 02 Jul 2026 23:15:43 +0000</pubDate><link>https://news.ycombinator.com/item?id=48768625</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48768625</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48768625</guid></item><item><title><![CDATA[New comment by estebank in "Since Linux 6.9, LUKS suspend stopped wiping disk-encryption keys from memory"]]></title><description><![CDATA[
<p>This is in effect a state machine, and when you have a type system more complex than C's you can encode state transitions in the type system (either by having state transitions explicitly return a new return type or by using sum types). You still need to architect the system to encode the invariants in types. No language will fix all logic bugs for free. But you <i>can</i> leverage language features to reduce their number.</p>
]]></description><pubDate>Thu, 02 Jul 2026 18:01:40 +0000</pubDate><link>https://news.ycombinator.com/item?id=48765180</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48765180</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48765180</guid></item><item><title><![CDATA[New comment by estebank in "Physical disc production ending in Jan 2028 for new games on PlayStation"]]></title><description><![CDATA[
<p>Like DVD before it, Blu-ray includes region locking as a feature (but apparently ~70% of disks don't bother with it, notably Paramount and Universal don't). Non-locked disks are marked as ABC (A is the Americas and Asia, B is Europe/Africa/Aus/NZ, C is Russia/India/China).</p>
]]></description><pubDate>Thu, 02 Jul 2026 17:53:39 +0000</pubDate><link>https://news.ycombinator.com/item?id=48765068</link><dc:creator>estebank</dc:creator><comments>https://news.ycombinator.com/item?id=48765068</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48765068</guid></item></channel></rss>