<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Advanced on</title><link>/tags/advanced/</link><description>Recent content in Advanced on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Mon, 22 Sep 2025 15:50:00 +0000</lastBuildDate><atom:link href="/tags/advanced/index.xml" rel="self" type="application/rss+xml"/><item><title>Lesson 10: Dependent Type Tricks — Encoding constraints in types</title><link>/post/rust/rust-type-dependent-types/</link><pubDate>Mon, 22 Sep 2025 15:50:00 +0000</pubDate><guid>/post/rust/rust-type-dependent-types/</guid><description>&lt;p&gt;There&amp;rsquo;s a running joke in the Rust community: &amp;ldquo;Rust has a dependent type system, it just doesn&amp;rsquo;t know it.&amp;rdquo; And like most good jokes, there&amp;rsquo;s truth in it. Rust doesn&amp;rsquo;t have &lt;em&gt;real&lt;/em&gt; dependent types like Idris or Agda, where types can depend on arbitrary runtime values. But with const generics, sealed constructors, and some creative type engineering, you can get surprisingly close.&lt;/p&gt;
&lt;p&gt;This final lesson is about pushing Rust&amp;rsquo;s type system to its absolute limits — encoding constraints that most people assume you need a dependently-typed language for.&lt;/p&gt;</description></item><item><title>Lesson 9: Proof Witnesses — Types as proofs</title><link>/post/rust/rust-type-proof-witnesses/</link><pubDate>Fri, 19 Sep 2025 13:22:00 +0000</pubDate><guid>/post/rust/rust-type-proof-witnesses/</guid><description>&lt;p&gt;The moment this clicked for me was when I was reviewing a crate that had a function signature like &lt;code&gt;fn process(data: &amp;amp;[u8], _proof: NonEmpty&amp;lt;'_&amp;gt;)&lt;/code&gt;. That second argument carried &lt;em&gt;no data&lt;/em&gt;. It was zero-sized. But you could only construct it by proving — through code that the compiler checked — that the slice was non-empty. The proof existed at compile time. At runtime, it was nothing.&lt;/p&gt;
&lt;p&gt;Types as proofs. Once you see it, you can&amp;rsquo;t unsee it.&lt;/p&gt;</description></item><item><title>Lesson 8: Sealed Traits — Closing extension points</title><link>/post/rust/rust-type-sealed-traits/</link><pubDate>Tue, 16 Sep 2025 09:38:00 +0000</pubDate><guid>/post/rust/rust-type-sealed-traits/</guid><description>&lt;p&gt;I was designing a public API for a parser library when I realized I had a problem. I wanted users to &lt;em&gt;use&lt;/em&gt; my trait — call its methods, pass it as a bound — but I did &lt;em&gt;not&lt;/em&gt; want them implementing it for their own types. Every new implementation would need to maintain invariants that I couldn&amp;rsquo;t enforce through the trait interface alone. If someone implemented it wrong, they&amp;rsquo;d get subtly broken behavior with no good error message.&lt;/p&gt;</description></item><item><title>Lesson 7: Type-Level Programming — Computing with types</title><link>/post/rust/rust-type-type-level-integers/</link><pubDate>Sat, 13 Sep 2025 11:15:00 +0000</pubDate><guid>/post/rust/rust-type-type-level-integers/</guid><description>&lt;p&gt;There&amp;rsquo;s a moment in every Rust programmer&amp;rsquo;s journey where they look at &lt;code&gt;typenum&lt;/code&gt; or some const-generics trick and think: &amp;ldquo;Wait, we&amp;rsquo;re doing &lt;em&gt;math&lt;/em&gt; at compile time? With the &lt;em&gt;type checker&lt;/em&gt;?&amp;rdquo; Yes. Yes we are. And it&amp;rsquo;s not a curiosity — it&amp;rsquo;s the foundation for things like fixed-size matrices, compile-time dimension checking, and provably correct buffer sizes.&lt;/p&gt;
&lt;p&gt;I first encountered type-level integers when I needed a matrix library that could guarantee at compile time that you couldn&amp;rsquo;t multiply a 3x4 matrix by a 2x5 matrix. The dimensions had to match, and I wanted the compiler — not a runtime assertion — to enforce it.&lt;/p&gt;</description></item><item><title>Lesson 6: Variance — Covariance, contravariance, invariance</title><link>/post/rust/rust-type-variance/</link><pubDate>Thu, 11 Sep 2025 16:42:00 +0000</pubDate><guid>/post/rust/rust-type-variance/</guid><description>&lt;p&gt;Variance is the topic that made me realize I didn&amp;rsquo;t actually understand Rust&amp;rsquo;s type system as well as I thought I did. I&amp;rsquo;d been writing Rust for over a year, had shipped production code, even written some unsafe blocks — and then I hit a lifetime error that I could not explain. The borrow checker was rejecting code that looked perfectly fine. Turns out, variance was the reason.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve ever had a lifetime error that made no sense, variance might be the missing piece.&lt;/p&gt;</description></item><item><title>Lesson 5: Existential Types — impl Trait in depth</title><link>/post/rust/rust-type-existential/</link><pubDate>Tue, 09 Sep 2025 07:28:00 +0000</pubDate><guid>/post/rust/rust-type-existential/</guid><description>&lt;p&gt;I used &lt;code&gt;impl Trait&lt;/code&gt; for months thinking it was just syntactic sugar for generics. &amp;ldquo;It&amp;rsquo;s the same as a type parameter, right? Just shorter?&amp;rdquo; No. It&amp;rsquo;s fundamentally different, and understanding &lt;em&gt;how&lt;/em&gt; it&amp;rsquo;s different unlocks patterns that are genuinely impossible with plain generics.&lt;/p&gt;
&lt;p&gt;Let me show you.&lt;/p&gt;
&lt;h2 id="two-positions-two-meanings"&gt;Two Positions, Two Meanings&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;impl Trait&lt;/code&gt; means completely different things depending on where you use it:&lt;/p&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;// Argument position: &amp;#34;I accept any type that implements Iterator&amp;#34;
&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;count_items&lt;/span&gt;(iter: &lt;span style="color:#a6e22e"&gt;impl&lt;/span&gt; Iterator&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Item &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; &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; iter.count()
&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;// Return position: &amp;#34;I return some specific type that implements Iterator,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// but I&amp;#39;m not telling you which one&amp;#34;
&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;make_numbers&lt;/span&gt;() -&amp;gt; &lt;span style="color:#a6e22e"&gt;impl&lt;/span&gt; Iterator&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Item &lt;span style="color:#f92672"&gt;=&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;).filter(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;x&lt;span style="color:#f92672"&gt;|&lt;/span&gt; x &lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&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;In argument position, the &lt;em&gt;caller&lt;/em&gt; chooses the concrete type. In return position, the &lt;em&gt;function&lt;/em&gt; chooses — and the caller can&amp;rsquo;t see what it picked. These are fundamentally different concepts from type theory.&lt;/p&gt;</description></item><item><title>Lesson 4: Simulating Higher-Kinded Types in Rust — The workarounds</title><link>/post/rust/rust-type-higher-kinded/</link><pubDate>Sun, 07 Sep 2025 19:03:00 +0000</pubDate><guid>/post/rust/rust-type-higher-kinded/</guid><description>&lt;p&gt;Every time someone on Reddit says &amp;ldquo;Rust can&amp;rsquo;t do higher-kinded types,&amp;rdquo; a part of me wants to respond with a 200-line code block that proves them&amp;hellip; well, partially wrong. Rust doesn&amp;rsquo;t have &lt;em&gt;native&lt;/em&gt; HKTs, that&amp;rsquo;s true. But the workarounds are surprisingly expressive, and with GATs (generic associated types) now stable, we can get &lt;em&gt;most&lt;/em&gt; of what you&amp;rsquo;d want from HKTs in practice.&lt;/p&gt;
&lt;p&gt;Let me walk you through the problem, why it matters, and the patterns that let you work around it.&lt;/p&gt;</description></item><item><title>Lesson 3: Session Types — Protocol safety at compile time</title><link>/post/rust/rust-type-session-types/</link><pubDate>Fri, 05 Sep 2025 10:45:00 +0000</pubDate><guid>/post/rust/rust-type-session-types/</guid><description>&lt;p&gt;I once spent three days debugging a distributed system where two services were sending messages in the wrong order. Service A expected a handshake acknowledgment before data, but Service B had been refactored to send data first. Both services compiled, both passed their unit tests, and both exploded in production. The protocol contract existed only in a Google Doc that nobody had updated.&lt;/p&gt;
&lt;p&gt;Session types fix this. They encode the &lt;em&gt;entire communication protocol&lt;/em&gt; in the type system — who sends what, in what order, and when. If you violate the protocol, your code doesn&amp;rsquo;t compile. Period.&lt;/p&gt;</description></item><item><title>Lesson 2: Advanced Typestate — Multi-state machines at compile time</title><link>/post/rust/rust-type-typestate-advanced/</link><pubDate>Wed, 03 Sep 2025 14:17:00 +0000</pubDate><guid>/post/rust/rust-type-typestate-advanced/</guid><description>&lt;p&gt;The first time I implemented a connection pool that &lt;em&gt;couldn&amp;rsquo;t&lt;/em&gt; be misused — not through discipline or documentation, but because the compiler physically rejected invalid state transitions — I felt like I&amp;rsquo;d discovered a cheat code. Not a runtime check. Not an assertion. A straight-up compiler error if you tried to read from a connection you hadn&amp;rsquo;t authenticated yet.&lt;/p&gt;
&lt;p&gt;This is the typestate pattern taken to its logical extreme. In Lesson 1 we saw the basics with &lt;code&gt;PhantomData&lt;/code&gt; and builder states. Now we&amp;rsquo;re going to encode full multi-state machines where every transition is checked at compile time. No runtime overhead. No state field to match on. Just the type system doing its job.&lt;/p&gt;</description></item><item><title>Lesson 1: Zero-Sized Types — PhantomData, () as design tools</title><link>/post/rust/rust-type-zero-sized/</link><pubDate>Mon, 01 Sep 2025 08:32:00 +0000</pubDate><guid>/post/rust/rust-type-zero-sized/</guid><description>&lt;p&gt;I remember staring at a struct definition in a library I was reading — it had a field of type &lt;code&gt;PhantomData&amp;lt;T&amp;gt;&lt;/code&gt; and I thought, &amp;ldquo;this does literally nothing.&amp;rdquo; The field takes up zero bytes. It has no runtime representation. Why on earth would you put a field in a struct that doesn&amp;rsquo;t exist at runtime?&lt;/p&gt;
&lt;p&gt;Turns out, zero-sized types are one of the most powerful design tools in Rust. They let you embed meaning into the type system without paying a single byte of overhead. Once you get this, you&amp;rsquo;ll start seeing ZSTs everywhere — and you&amp;rsquo;ll start using them yourself.&lt;/p&gt;</description></item></channel></rss>