<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Idiomatic-Rust on</title><link>/tags/idiomatic-rust/</link><description>Recent content in Idiomatic-Rust on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Wed, 22 May 2024 17:08:00 +0000</lastBuildDate><atom:link href="/tags/idiomatic-rust/index.xml" rel="self" type="application/rss+xml"/><item><title>Lesson 25: When to Reach for unsafe — And when not to</title><link>/post/rust/rust-idioms-unsafe-boundary/</link><pubDate>Wed, 22 May 2024 17:08:00 +0000</pubDate><guid>/post/rust/rust-idioms-unsafe-boundary/</guid><description>&lt;p&gt;This is the lesson I almost didn&amp;rsquo;t write. Not because &lt;code&gt;unsafe&lt;/code&gt; is hard to explain, but because most Rust developers will never need it — and I don&amp;rsquo;t want to encourage reaching for it prematurely. I&amp;rsquo;ve seen codebases riddled with &lt;code&gt;unsafe&lt;/code&gt; blocks because the developer didn&amp;rsquo;t know the safe alternative existed. That&amp;rsquo;s the worst outcome.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;unsafe&lt;/code&gt; exists for a reason. Understanding when it&amp;rsquo;s appropriate — and more importantly, when it isn&amp;rsquo;t — is part of being a competent Rust developer.&lt;/p&gt;</description></item><item><title>Lesson 24: Writing Great Rust Documentation — rustdoc that actually helps</title><link>/post/rust/rust-idioms-documentation/</link><pubDate>Mon, 20 May 2024 14:30:00 +0000</pubDate><guid>/post/rust/rust-idioms-documentation/</guid><description>&lt;p&gt;The Rust ecosystem has some of the best documentation I&amp;rsquo;ve seen in any language. And it&amp;rsquo;s not an accident — the tooling actively &lt;em&gt;encourages&lt;/em&gt; good documentation. Doc comments are first-class citizens. Examples in docs are compiled and tested. The standard library sets an impossibly high bar that crate authors actually try to meet.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re publishing a crate and the docs are an afterthought, you&amp;rsquo;re doing it wrong. Documentation is the API.&lt;/p&gt;</description></item><item><title>Lesson 23: Clippy Is Your Mentor — Listen to it</title><link>/post/rust/rust-idioms-clippy/</link><pubDate>Sat, 18 May 2024 10:55:00 +0000</pubDate><guid>/post/rust/rust-idioms-clippy/</guid><description>&lt;p&gt;I&amp;rsquo;ll say something controversial: Clippy taught me more about idiomatic Rust than any book. Not because it explains concepts — it doesn&amp;rsquo;t. But because it catches you every time you write non-idiomatic code and shows you the better way. It&amp;rsquo;s like having a senior Rust developer looking over your shoulder, constantly saying &amp;ldquo;there&amp;rsquo;s a cleaner way to do that.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;cargo clippy&lt;/code&gt; on every project. Every commit. No exceptions.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-clippy-is"&gt;What Clippy Is&lt;/h2&gt;
&lt;p&gt;Clippy is Rust&amp;rsquo;s official linter — over 700 lint rules that catch everything from style issues to actual bugs. It ships with rustup, so you already have it.&lt;/p&gt;</description></item><item><title>Lesson 22: Feature Flags and Conditional Compilation — cfg and features</title><link>/post/rust/rust-idioms-cfg-features/</link><pubDate>Thu, 16 May 2024 12:45:00 +0000</pubDate><guid>/post/rust/rust-idioms-cfg-features/</guid><description>&lt;p&gt;I once worked on a crate that pulled in 200+ transitive dependencies because it unconditionally depended on &lt;code&gt;tokio&lt;/code&gt;, &lt;code&gt;serde&lt;/code&gt;, &lt;code&gt;reqwest&lt;/code&gt;, and &lt;code&gt;tracing&lt;/code&gt;. Most users only needed one of those. The compile time was brutal, and the binary was enormous.&lt;/p&gt;
&lt;p&gt;Feature flags solve this. They let users opt into functionality they need and skip everything else. It&amp;rsquo;s the &amp;ldquo;pay for what you use&amp;rdquo; principle applied to compilation.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="cfg--conditional-compilation"&gt;cfg — Conditional Compilation&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;#[cfg(...)]&lt;/code&gt; attribute conditionally includes code based on compile-time configuration:&lt;/p&gt;</description></item><item><title>Lesson 21: The Turbofish ::&lt;&gt; — Explicit type parameters</title><link>/post/rust/rust-idioms-turbofish/</link><pubDate>Tue, 14 May 2024 08:22:00 +0000</pubDate><guid>/post/rust/rust-idioms-turbofish/</guid><description>&lt;p&gt;The first time I saw &lt;code&gt;::&amp;lt;&amp;gt;&lt;/code&gt; in Rust code, I thought someone was having a stroke at the keyboard. &lt;code&gt;collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;()&lt;/code&gt;? What is that colon-colon-angle-bracket monstrosity?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s called the turbofish. Named by the community because &lt;code&gt;::&amp;lt;&amp;gt;&lt;/code&gt; looks like a fish (&lt;code&gt;::&amp;lt;&amp;gt;&lt;/code&gt; — see the eyes and the mouth?). It&amp;rsquo;s goofy. It&amp;rsquo;s lovable. And once you understand it, you&amp;rsquo;ll use it constantly.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-the-turbofish-does"&gt;What the Turbofish Does&lt;/h2&gt;
&lt;p&gt;The turbofish provides explicit type parameters to generic functions or methods when the compiler can&amp;rsquo;t infer them.&lt;/p&gt;</description></item><item><title>Lesson 20: API Design Guidelines — The Rust way</title><link>/post/rust/rust-idioms-api-design/</link><pubDate>Sun, 12 May 2024 16:40:00 +0000</pubDate><guid>/post/rust/rust-idioms-api-design/</guid><description>&lt;p&gt;I&amp;rsquo;ve written APIs in a dozen languages, and Rust is the only one where the community has near-universal agreement on how APIs should look. There&amp;rsquo;s an unofficial (but incredibly thorough) Rust API Guidelines document, and most popular crates follow it closely. When you learn these conventions, every new crate feels familiar.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what I&amp;rsquo;ve distilled from reading hundreds of crate APIs and writing a few of my own.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="naming-conventions"&gt;Naming Conventions&lt;/h2&gt;
&lt;p&gt;Rust has strong naming conventions, and deviating from them makes your crate feel alien.&lt;/p&gt;</description></item><item><title>Lesson 19: PhantomData — Tagging types without runtime cost</title><link>/post/rust/rust-idioms-phantom-data/</link><pubDate>Fri, 10 May 2024 09:15:00 +0000</pubDate><guid>/post/rust/rust-idioms-phantom-data/</guid><description>&lt;p&gt;When I first saw &lt;code&gt;PhantomData&lt;/code&gt; in a codebase, I thought it was some kind of hack. A zero-sized field that exists only to satisfy the compiler? It felt like a workaround for a language limitation. But the more I used it, the more I realized it&amp;rsquo;s actually a precision tool — it lets you encode information in the type system without any runtime cost.&lt;/p&gt;
&lt;p&gt;We already used it in the typestate lesson. Now let&amp;rsquo;s understand it properly.&lt;/p&gt;</description></item><item><title>Lesson 18: Drop and RAII — Deterministic cleanup</title><link>/post/rust/rust-idioms-drop/</link><pubDate>Wed, 08 May 2024 11:30:00 +0000</pubDate><guid>/post/rust/rust-idioms-drop/</guid><description>&lt;p&gt;In Go, you write &lt;code&gt;defer f.Close()&lt;/code&gt; and hope you didn&amp;rsquo;t forget one. In Python, you use &lt;code&gt;with&lt;/code&gt; blocks and hope the context manager is implemented correctly. In Java, you use try-with-resources and hope &lt;code&gt;AutoCloseable.close()&lt;/code&gt; doesn&amp;rsquo;t throw. In C, you write &lt;code&gt;free()&lt;/code&gt; and pray.&lt;/p&gt;
&lt;p&gt;In Rust, cleanup happens automatically when a value goes out of scope. Always. No exceptions. No forgetting. That&amp;rsquo;s RAII — Resource Acquisition Is Initialization — and the &lt;code&gt;Drop&lt;/code&gt; trait is how Rust implements it.&lt;/p&gt;</description></item><item><title>Lesson 17: Zero-Cost Abstractions — What it actually means</title><link>/post/rust/rust-idioms-zero-cost/</link><pubDate>Mon, 06 May 2024 14:52:00 +0000</pubDate><guid>/post/rust/rust-idioms-zero-cost/</guid><description>&lt;p&gt;&amp;ldquo;Zero-cost abstractions&amp;rdquo; is Rust&amp;rsquo;s most-repeated promise and its most-misunderstood concept. People hear &amp;ldquo;zero cost&amp;rdquo; and think &amp;ldquo;free.&amp;rdquo; It doesn&amp;rsquo;t mean free. It means: &lt;strong&gt;you don&amp;rsquo;t pay for what you don&amp;rsquo;t use, and what you do use, you couldn&amp;rsquo;t hand-code any better.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a Bjarne Stroustrup quote, originally about C++. But Rust actually delivers on it in ways C++ often doesn&amp;rsquo;t.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-zero-cost-actually-means"&gt;What Zero-Cost Actually Means&lt;/h2&gt;
&lt;p&gt;Consider iterators. In Python, iterator chains create intermediate objects. In Java, streams can have overhead from boxing and virtual dispatch. In Rust:&lt;/p&gt;</description></item><item><title>Lesson 16: Enums Over Booleans — Make illegal states unrepresentable</title><link>/post/rust/rust-idioms-enums-over-bools/</link><pubDate>Sun, 05 May 2024 08:17:00 +0000</pubDate><guid>/post/rust/rust-idioms-enums-over-bools/</guid><description>&lt;p&gt;I once spent an entire afternoon debugging a function with this signature: &lt;code&gt;process(data, true, false, true)&lt;/code&gt;. Three booleans. What did they mean? I had to read the function definition every single time I encountered a call site. Is &lt;code&gt;true&lt;/code&gt; for &amp;ldquo;verbose&amp;rdquo;? For &amp;ldquo;dry-run&amp;rdquo;? For &amp;ldquo;force&amp;rdquo;?&lt;/p&gt;
&lt;p&gt;Booleans are the most overused type in programming. They encode exactly one bit of information — yes or no — and they tell you nothing about &lt;em&gt;what question they&amp;rsquo;re answering&lt;/em&gt;. Enums fix this.&lt;/p&gt;</description></item><item><title>Lesson 15: Exhaustive Matching — Let the compiler help</title><link>/post/rust/rust-idioms-exhaustive-matching/</link><pubDate>Fri, 03 May 2024 22:08:00 +0000</pubDate><guid>/post/rust/rust-idioms-exhaustive-matching/</guid><description>&lt;p&gt;A teammate once added a new payment method to our system — &lt;code&gt;CryptoCurrency&lt;/code&gt; — and forgot to update the fee calculation logic. In production. For three weeks. Nobody noticed because the switch statement in Java had a &lt;code&gt;default&lt;/code&gt; case that silently applied a 0% fee. Free crypto transfers for everyone.&lt;/p&gt;
&lt;p&gt;In Rust, the compiler would have caught this the moment the new variant was added. That&amp;rsquo;s exhaustive matching — and it&amp;rsquo;s one of Rust&amp;rsquo;s most underappreciated features.&lt;/p&gt;</description></item><item><title>Lesson 14: derive Is Your Best Friend — The macros you should always use</title><link>/post/rust/rust-idioms-derive/</link><pubDate>Thu, 02 May 2024 10:30:00 +0000</pubDate><guid>/post/rust/rust-idioms-derive/</guid><description>&lt;p&gt;I review a lot of Rust code, and one of my biggest pet peeves is types without &lt;code&gt;#[derive(Debug)]&lt;/code&gt;. You hit an error, you try to print the value, and you get that lovely message: &amp;ldquo;MyStruct doesn&amp;rsquo;t implement Debug.&amp;rdquo; Then you have to go add it, recompile, and try again.&lt;/p&gt;
&lt;p&gt;Just derive it from the start. Derive liberally. Your future self will thank you.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-derives-you-should-almost-always-use"&gt;The Derives You Should Almost Always Use&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s my standard starting point for any struct or enum:&lt;/p&gt;</description></item><item><title>Lesson 13: Display and Debug — Formatting done right</title><link>/post/rust/rust-idioms-display-debug/</link><pubDate>Tue, 30 Apr 2024 18:45:00 +0000</pubDate><guid>/post/rust/rust-idioms-display-debug/</guid><description>&lt;p&gt;Pop quiz: what&amp;rsquo;s the difference between &lt;code&gt;{}&lt;/code&gt; and &lt;code&gt;{:?}&lt;/code&gt; in a &lt;code&gt;println!&lt;/code&gt;? If your answer is &amp;ldquo;one looks prettier,&amp;rdquo; you&amp;rsquo;re not wrong — but you&amp;rsquo;re missing the bigger picture.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Display&lt;/code&gt; and &lt;code&gt;Debug&lt;/code&gt; serve fundamentally different audiences. &lt;code&gt;Display&lt;/code&gt; is for humans — end users, log readers, UI consumers. &lt;code&gt;Debug&lt;/code&gt; is for developers — it&amp;rsquo;s what you see in error messages, test failures, and debug sessions. Conflating the two leads to types that are either too verbose for users or too opaque for debugging.&lt;/p&gt;</description></item><item><title>Lesson 12: Designing Error Types — thiserror vs anyhow</title><link>/post/rust/rust-idioms-error-design/</link><pubDate>Mon, 29 Apr 2024 12:18:00 +0000</pubDate><guid>/post/rust/rust-idioms-error-design/</guid><description>&lt;p&gt;I&amp;rsquo;ve seen two extremes in Rust error handling. On one end: &lt;code&gt;Box&amp;lt;dyn std::error::Error&amp;gt;&lt;/code&gt; everywhere, a stringly-typed mess where you can&amp;rsquo;t distinguish a network timeout from a parse failure. On the other end: 47 custom error types with hand-written &lt;code&gt;Display&lt;/code&gt; and &lt;code&gt;From&lt;/code&gt; implementations, an over-engineered cathedral of boilerplate.&lt;/p&gt;
&lt;p&gt;The right answer is somewhere in the middle. And the two crates that get you there are &lt;code&gt;thiserror&lt;/code&gt; and &lt;code&gt;anyhow&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-wrong-ways"&gt;The Wrong Ways&lt;/h2&gt;
&lt;h3 id="wrong-way-1-string-errors"&gt;Wrong Way #1: String Errors&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;parse_config&lt;/span&gt;(input: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;u16&lt;/span&gt;, String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; port: &lt;span style="color:#66d9ef"&gt;u16&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; input.parse().map_err(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;e&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;bad port: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e))&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; port &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;port must be &amp;gt;= 1024&amp;#34;&lt;/span&gt;.to_string());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(port)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The caller gets a &lt;code&gt;String&lt;/code&gt;. What can they do with it? Print it. That&amp;rsquo;s about it. They can&amp;rsquo;t match on error variants, can&amp;rsquo;t programmatically decide how to handle different failures, can&amp;rsquo;t distinguish between &amp;ldquo;bad port&amp;rdquo; and &amp;ldquo;port too low.&amp;rdquo; It&amp;rsquo;s a dead end.&lt;/p&gt;</description></item><item><title>Lesson 11: Cow — Clone on write for flexible APIs</title><link>/post/rust/rust-idioms-cow/</link><pubDate>Sat, 27 Apr 2024 15:33:00 +0000</pubDate><guid>/post/rust/rust-idioms-cow/</guid><description>&lt;p&gt;There&amp;rsquo;s a function signature dilemma that every Rust developer hits: should this function return &lt;code&gt;&amp;amp;str&lt;/code&gt; or &lt;code&gt;String&lt;/code&gt;? If you return &lt;code&gt;&amp;amp;str&lt;/code&gt;, you avoid allocation — but sometimes you &lt;em&gt;need&lt;/em&gt; to create a new string. If you return &lt;code&gt;String&lt;/code&gt;, you allocate every time — even when you don&amp;rsquo;t need to.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Cow&lt;/code&gt; says: &amp;ldquo;Why not both?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The name stands for &amp;ldquo;Clone on Write,&amp;rdquo; and it&amp;rsquo;s one of those types that seems weird until you use it — and then you wonder how you lived without it.&lt;/p&gt;</description></item><item><title>Lesson 10: Deref Coercion — Why &amp;String works as &amp;str</title><link>/post/rust/rust-idioms-deref-coercion/</link><pubDate>Thu, 25 Apr 2024 21:10:00 +0000</pubDate><guid>/post/rust/rust-idioms-deref-coercion/</guid><description>&lt;p&gt;Here&amp;rsquo;s something that confused me for weeks when I started Rust: I&amp;rsquo;d write a function that takes &lt;code&gt;&amp;amp;str&lt;/code&gt;, and I could pass it a &lt;code&gt;&amp;amp;String&lt;/code&gt;. I&amp;rsquo;d write a function that takes &lt;code&gt;&amp;amp;[i32]&lt;/code&gt;, and I could pass it a &lt;code&gt;&amp;amp;Vec&amp;lt;i32&amp;gt;&lt;/code&gt;. I&amp;rsquo;d use &lt;code&gt;*&lt;/code&gt; to dereference a &lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt; and get a &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;How? Why? The answer is &lt;code&gt;Deref&lt;/code&gt; coercion — one of Rust&amp;rsquo;s most elegant features, and one of the most poorly explained.&lt;/p&gt;</description></item><item><title>Lesson 9: From and Into — Seamless type conversions</title><link>/post/rust/rust-idioms-from-into/</link><pubDate>Wed, 24 Apr 2024 07:55:00 +0000</pubDate><guid>/post/rust/rust-idioms-from-into/</guid><description>&lt;p&gt;The first time I saw &lt;code&gt;.into()&lt;/code&gt; in Rust code, I was baffled. &amp;ldquo;Into &lt;em&gt;what&lt;/em&gt;?&amp;rdquo; There was no type annotation, no explicit conversion function, just &lt;code&gt;.into()&lt;/code&gt; hanging off a value like it knew exactly what to become. And somehow the compiler figured it out.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s the &lt;code&gt;From&lt;/code&gt;/&lt;code&gt;Into&lt;/code&gt; trait pair. It&amp;rsquo;s one of the most-used patterns in idiomatic Rust, and once you understand it, your APIs will feel dramatically smoother.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-basics-from-and-into-are-mirror-images"&gt;The Basics: &lt;code&gt;From&lt;/code&gt; and &lt;code&gt;Into&lt;/code&gt; Are Mirror Images&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// If you implement From&amp;lt;A&amp;gt; for B...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; From&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; MyType {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;(value: &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MyType(value)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ...you get Into&amp;lt;B&amp;gt; for A for free
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; x: &lt;span style="color:#a6e22e"&gt;MyType&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;42.&lt;/span&gt;into();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Always implement &lt;code&gt;From&lt;/code&gt;, never &lt;code&gt;Into&lt;/code&gt; directly.&lt;/strong&gt; The standard library provides a blanket implementation: if &lt;code&gt;From&amp;lt;A&amp;gt;&lt;/code&gt; exists for &lt;code&gt;B&lt;/code&gt;, then &lt;code&gt;Into&amp;lt;B&amp;gt;&lt;/code&gt; is automatically available for &lt;code&gt;A&lt;/code&gt;. Implementing &lt;code&gt;Into&lt;/code&gt; directly doesn&amp;rsquo;t give you the reverse.&lt;/p&gt;</description></item><item><title>Lesson 8: The Builder Pattern in Rust — Ergonomic construction</title><link>/post/rust/rust-idioms-builder/</link><pubDate>Mon, 22 Apr 2024 19:42:00 +0000</pubDate><guid>/post/rust/rust-idioms-builder/</guid><description>&lt;p&gt;Every Rust dev eventually runs into the &amp;ldquo;struct with 12 fields&amp;rdquo; problem. You&amp;rsquo;ve got a configuration type. Some fields are required, some are optional, some have sensible defaults. In Java, you&amp;rsquo;d use a Builder. In Python, you&amp;rsquo;d use keyword arguments. In Go, you&amp;rsquo;d use functional options.&lt;/p&gt;
&lt;p&gt;In Rust? You have options. And one of them is clearly better than the rest.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-problem-constructor-explosion"&gt;The Problem: Constructor Explosion&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerConfig&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; host: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#66d9ef"&gt;u16&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_connections: &lt;span style="color:#66d9ef"&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout_secs: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tls_enabled: &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; log_level: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; workers: &lt;span style="color:#66d9ef"&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// This is painful
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; config &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ServerConfig {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; host: String::from(&lt;span style="color:#e6db74"&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_connections: &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout_secs: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tls_enabled: &lt;span style="color:#a6e22e"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; log_level: String::from(&lt;span style="color:#e6db74"&gt;&amp;#34;info&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; workers: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every field must be specified. There&amp;rsquo;s no concept of &amp;ldquo;default.&amp;rdquo; If you add a new field later, every construction site breaks. And callers have no idea which values are &amp;ldquo;important&amp;rdquo; and which are &amp;ldquo;just use the default.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Lesson 7: The Newtype Pattern — Type safety for free</title><link>/post/rust/rust-idioms-newtype/</link><pubDate>Sun, 21 Apr 2024 13:15:00 +0000</pubDate><guid>/post/rust/rust-idioms-newtype/</guid><description>&lt;p&gt;True story: a Mars orbiter was lost because one team used pounds and another used newtons. Same numeric type, different semantic meanings. $327 million, gone.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;d think we&amp;rsquo;d have learned. But I still see codebases where user IDs, product IDs, and order IDs are all &lt;code&gt;i64&lt;/code&gt;. Where distances are &lt;code&gt;f64&lt;/code&gt; whether they&amp;rsquo;re meters or feet. Where an email address is just a &lt;code&gt;String&lt;/code&gt; that you hope someone validated.&lt;/p&gt;
&lt;p&gt;The newtype pattern fixes this. It gives you type safety with zero runtime cost.&lt;/p&gt;</description></item><item><title>Lesson 6: The Typestate Pattern — Compile-time state machines</title><link>/post/rust/rust-idioms-type-state/</link><pubDate>Fri, 19 Apr 2024 10:28:00 +0000</pubDate><guid>/post/rust/rust-idioms-type-state/</guid><description>&lt;p&gt;I once spent two days debugging a production issue where someone called &lt;code&gt;.send()&lt;/code&gt; on an HTTP request builder &lt;em&gt;before&lt;/em&gt; setting the URL. The code compiled fine — it was a runtime error that only surfaced under specific conditions. In Python. In Java. In Go. This kind of bug is everywhere.&lt;/p&gt;
&lt;p&gt;In Rust, you can make it literally impossible to compile. The typestate pattern encodes state transitions into the type system. If the state machine says you can&amp;rsquo;t send before setting a URL, the compiler enforces it. Not with runtime checks. Not with assertions. With &lt;em&gt;types&lt;/em&gt;.&lt;/p&gt;</description></item><item><title>Lesson 5: Iterator Chains Over Manual Loops — Functional Rust</title><link>/post/rust/rust-idioms-iterator-chains/</link><pubDate>Thu, 18 Apr 2024 16:03:00 +0000</pubDate><guid>/post/rust/rust-idioms-iterator-chains/</guid><description>&lt;p&gt;I used to write Rust like I was still writing C — &lt;code&gt;for&lt;/code&gt; loops everywhere, mutable accumulators, index variables. The code worked, but it was &lt;em&gt;loud&lt;/em&gt;. Five lines to express what should be one. Then I started using iterator chains, and honestly? I&amp;rsquo;m never going back.&lt;/p&gt;
&lt;p&gt;Iterator chains aren&amp;rsquo;t just syntactic sugar. They&amp;rsquo;re often &lt;em&gt;faster&lt;/em&gt; than hand-written loops because the compiler can optimize them better. Zero-cost abstractions in action.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-imperative-way-vs-the-idiomatic-way"&gt;The Imperative Way vs The Idiomatic Way&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a task: given a list of strings, find all that start with &amp;ldquo;error:&amp;rdquo;, strip the prefix, trim whitespace, and collect the results.&lt;/p&gt;</description></item><item><title>Lesson 4: if let and while let — Concise pattern matching</title><link>/post/rust/rust-idioms-if-let-while-let/</link><pubDate>Tue, 16 Apr 2024 08:45:00 +0000</pubDate><guid>/post/rust/rust-idioms-if-let-while-let/</guid><description>&lt;p&gt;There&amp;rsquo;s a special kind of code smell that I call &amp;ldquo;match bloat&amp;rdquo; — when you write a six-line &lt;code&gt;match&lt;/code&gt; statement to handle a single variant and throw an underscore wildcard on everything else. I wrote hundreds of these before discovering that Rust has a better way.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re writing &lt;code&gt;match&lt;/code&gt; just to handle one case, you&amp;rsquo;re doing too much work.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-problem-match-bloat"&gt;The Problem: Match Bloat&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s code I see all the time, especially from developers coming from the previous lesson on &lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Lesson 3: Option and Result Are Your Control Flow — Stop using sentinel values</title><link>/post/rust/rust-idioms-option-result/</link><pubDate>Sun, 14 Apr 2024 11:22:00 +0000</pubDate><guid>/post/rust/rust-idioms-option-result/</guid><description>&lt;p&gt;I once inherited a C codebase where &lt;code&gt;-1&lt;/code&gt; meant &amp;ldquo;not found,&amp;rdquo; &lt;code&gt;0&lt;/code&gt; meant &amp;ldquo;error,&amp;rdquo; and &lt;code&gt;NULL&lt;/code&gt; meant&amp;hellip; well, it depended on the function. Sometimes it meant &amp;ldquo;empty,&amp;rdquo; sometimes &amp;ldquo;uninitialized,&amp;rdquo; sometimes &amp;ldquo;we ran out of memory.&amp;rdquo; The codebase had roughly 40 unique sentinel values across different modules, and half the bugs were someone forgetting which magic number meant what.&lt;/p&gt;
&lt;p&gt;Rust looked at that mess and said: &amp;ldquo;How about we just&amp;hellip; don&amp;rsquo;t.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Lesson 2: Borrow Strategically — &amp;T, &amp;mut T, and when to clone</title><link>/post/rust/rust-idioms-borrowing-patterns/</link><pubDate>Fri, 12 Apr 2024 14:37:00 +0000</pubDate><guid>/post/rust/rust-idioms-borrowing-patterns/</guid><description>&lt;p&gt;A colleague once showed me their Rust code where every function parameter was &lt;code&gt;String&lt;/code&gt; — never &lt;code&gt;&amp;amp;str&lt;/code&gt;, never &lt;code&gt;&amp;amp;String&lt;/code&gt;. When I asked why, they said &amp;ldquo;the borrow checker kept yelling at me, so I just take ownership of everything.&amp;rdquo; Classic.&lt;/p&gt;
&lt;p&gt;I get it. The borrow checker can feel like an overzealous hall monitor. But once you understand the borrowing rules — really understand them — you&amp;rsquo;ll realize it&amp;rsquo;s not restricting you. It&amp;rsquo;s showing you a better design.&lt;/p&gt;</description></item><item><title>Lesson 1: Think in Ownership — Not pointers</title><link>/post/rust/rust-idioms-ownership-thinking/</link><pubDate>Wed, 10 Apr 2024 09:14:00 +0000</pubDate><guid>/post/rust/rust-idioms-ownership-thinking/</guid><description>&lt;p&gt;I spent three months fighting the borrow checker before I realized the problem wasn&amp;rsquo;t the borrow checker — it was me. I kept thinking in C++ pointers and Java references. Every &lt;code&gt;String&lt;/code&gt; was just &amp;ldquo;data on the heap.&amp;rdquo; Every function call was &amp;ldquo;passing a reference.&amp;rdquo; And every compiler error felt like Rust was being unreasonable.&lt;/p&gt;
&lt;p&gt;It wasn&amp;rsquo;t. I was just thinking about memory the wrong way.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-cjava-mental-model-and-why-it-fails"&gt;The C++/Java Mental Model (And Why It Fails)&lt;/h2&gt;
&lt;p&gt;If you come from C++, your brain maps everything to raw pointers, smart pointers, or references. If you come from Java/Python/Go, everything is a reference behind the scenes — you never think about who owns what, because the GC handles it.&lt;/p&gt;</description></item></channel></rss>