<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Reflection on</title><link>/tags/reflection/</link><description>Recent content in Reflection on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Tue, 10 Jun 2025 00:00:00 +0000</lastBuildDate><atom:link href="/tags/reflection/index.xml" rel="self" type="application/rss+xml"/><item><title>Lesson 7: go:generate and Code Generation — Let the machine write the boring code</title><link>/post/go/go-reflect-codegen/</link><pubDate>Tue, 10 Jun 2025 00:00:00 +0000</pubDate><guid>/post/go/go-reflect-codegen/</guid><description>&lt;p&gt;&lt;code&gt;go:generate&lt;/code&gt; is Go&amp;rsquo;s mechanism for attaching arbitrary code generation commands to your source files. It is not magic — it is a convention that tells &lt;code&gt;go generate&lt;/code&gt; which commands to run and where. When you run &lt;code&gt;go generate ./...&lt;/code&gt;, the tool reads every &lt;code&gt;//go:generate&lt;/code&gt; comment in your source tree and executes the commands they reference. What those commands produce is up to you: &lt;code&gt;String()&lt;/code&gt; methods for enum types, serialization code, mock implementations, database query functions, or anything else you can express as a code generator.&lt;/p&gt;</description></item><item><title>Lesson 6: Avoiding Reflection — Generics and code generation often win</title><link>/post/go/go-reflect-avoiding/</link><pubDate>Tue, 08 Apr 2025 00:00:00 +0000</pubDate><guid>/post/go/go-reflect-avoiding/</guid><description>&lt;p&gt;After spending several lessons on what reflection can do, it is worth turning the question around: when should you specifically choose not to use reflection, even when it would work? The answer is almost always &amp;ldquo;when you have a statically typed alternative,&amp;rdquo; because statically typed code is faster, catches errors at compile time rather than runtime, and is easier for both humans and tools to reason about.&lt;/p&gt;
&lt;p&gt;Go 1.18 added generics, which eliminated one of the most common justifications for reflection: writing algorithms that work on slices, maps, or other containers of unknown element type. Code generation eliminates another: producing type-specific serializers, converters, and mappers that are faster than reflection can ever be. Knowing when to reach for these alternatives instead of reflection is part of writing mature Go.&lt;/p&gt;</description></item><item><title>Lesson 5: Validation Frameworks — Reflect once, validate everywhere</title><link>/post/go/go-reflect-validation/</link><pubDate>Mon, 10 Feb 2025 00:00:00 +0000</pubDate><guid>/post/go/go-reflect-validation/</guid><description>&lt;p&gt;Input validation is one of those problems that looks solved until you realize you are writing the same type of check — not nil, min length, valid email format, required when other field is set — dozens of times across dozens of handlers. Centralizing these rules without reflection means either a massive switch statement or hand-writing a validation function for every struct in your application. Reflection makes it possible to declare validation rules once, at the struct, and enforce them automatically everywhere that struct is validated.&lt;/p&gt;</description></item><item><title>Lesson 4: Building a Serializer — encoding/json under the hood</title><link>/post/go/go-reflect-serializer/</link><pubDate>Thu, 28 Nov 2024 00:00:00 +0000</pubDate><guid>/post/go/go-reflect-serializer/</guid><description>&lt;p&gt;&lt;code&gt;encoding/json&lt;/code&gt; is Go&amp;rsquo;s most-used package and one of its most instructive implementations. Under the hood it is almost entirely reflection: it inspects struct field types, reads &lt;code&gt;json&lt;/code&gt; tags, handles pointer dereferences, recurses into nested structs, and handles special cases like &lt;code&gt;time.Time&lt;/code&gt; and &lt;code&gt;json.Marshaler&lt;/code&gt; interface implementations. Building a simplified version of a struct serializer from scratch is the best way to understand both how reflection works in practice and why &lt;code&gt;encoding/json&lt;/code&gt; makes the design choices it does.&lt;/p&gt;</description></item><item><title>Lesson 3: Struct Tags — Metadata your compiler ignores but your framework reads</title><link>/post/go/go-reflect-struct-tags/</link><pubDate>Tue, 08 Oct 2024 00:00:00 +0000</pubDate><guid>/post/go/go-reflect-struct-tags/</guid><description>&lt;p&gt;Struct tags are one of Go&amp;rsquo;s most practically useful metaprogramming tools and one of its least formally documented features. The syntax is simple — a raw string literal after the field type in a struct — but the convention built on top of it powers nearly every serialization library, ORM, validator, and configuration loader in the ecosystem. Understanding how tags work at the reflection level demystifies why &lt;code&gt;encoding/json&lt;/code&gt; knows to use &lt;code&gt;omitempty&lt;/code&gt;, why &lt;code&gt;database/sql&lt;/code&gt; scanners can map column names to struct fields, and how you can build your own tag-driven behavior.&lt;/p&gt;</description></item><item><title>Lesson 2: Performance Costs — reflect.ValueOf is not free</title><link>/post/go/go-reflect-performance/</link><pubDate>Thu, 15 Aug 2024 00:00:00 +0000</pubDate><guid>/post/go/go-reflect-performance/</guid><description>&lt;p&gt;Every time I see reflection in a hot path, I know there is a performance conversation waiting to happen. Reflection in Go is not arbitrarily slow — it is predictably and measurably slow in specific ways. Understanding those costs, benchmarking them in your context, and knowing the standard mitigation patterns (primarily caching) lets you use reflection where it belongs without making your application noticeably slower.&lt;/p&gt;
&lt;p&gt;The performance story of reflection has two parts: the cost of type inspection (getting a &lt;code&gt;reflect.Type&lt;/code&gt;, reading fields, checking kinds) and the cost of value operations (getting a &lt;code&gt;reflect.Value&lt;/code&gt;, reading or setting field values, calling methods). Type inspection is expensive the first time and cheap if cached. Value operations are expensive every time and there is no way to avoid that cost except to reduce how often you do them.&lt;/p&gt;</description></item><item><title>Lesson 1: When Reflection Is Justified — The last resort that sometimes is the only resort</title><link>/post/go/go-reflect-when-justified/</link><pubDate>Fri, 28 Jun 2024 00:00:00 +0000</pubDate><guid>/post/go/go-reflect-when-justified/</guid><description>&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;reflect&lt;/code&gt; package carries a reputation: &amp;ldquo;don&amp;rsquo;t use it unless you have to.&amp;rdquo; That advice is correct but incomplete. Understanding &lt;em&gt;when&lt;/em&gt; you actually have to use it — and when you are just reaching for it out of habit from dynamic languages — is the difference between reflection that pulls its weight and reflection that creates unmaintainable, slow, panic-prone code that confuses every future reader of the codebase.&lt;/p&gt;
&lt;p&gt;Reflection lets Go inspect and manipulate values, types, and struct fields at runtime without static type information. It is the mechanism behind &lt;code&gt;encoding/json&lt;/code&gt;, &lt;code&gt;database/sql&lt;/code&gt;&amp;rsquo;s row scanning, struct validators, ORM frameworks, and dependency injection containers. It is also the mechanism behind a lot of code that should have just used a map or an interface.&lt;/p&gt;</description></item></channel></rss>