index.html (37918B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <title> 6 Why People Love to Hate Go · Jack Mordaunt 7 </title> 8 <meta charset="utf-8"> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 10 <meta name="color-scheme" content="light dark"> 11 12 13 14 15 <meta name="author" content="Jack Mordaunt"> 16 <meta name="description" content="Go has good ideas but never gives them to you completely."> 17 <meta name="keywords" content="blog,developer,personal,software,robust,performance,sovereign"> 18 19 20 21 <meta name="twitter:card" content="summary"> 22 <meta name="twitter:title" content="Why People Love to Hate Go"> 23 <meta name="twitter:description" content="Go has good ideas but never gives them to you completely."> 24 25 <meta property="og:url" content="http://jackmordaunt.com/posts/why-people-hate-go/"> 26 <meta property="og:site_name" content="Jack Mordaunt"> 27 <meta property="og:title" content="Why People Love to Hate Go"> 28 <meta property="og:description" content="Go has good ideas but never gives them to you completely."> 29 <meta property="og:locale" content="en"> 30 <meta property="og:type" content="article"> 31 <meta property="article:section" content="posts"> 32 <meta property="article:published_time" content="2025-07-23T14:16:55-03:00"> 33 <meta property="article:modified_time" content="2025-07-23T14:16:55-03:00"> 34 <meta property="article:tag" content="Go"> 35 <meta property="article:tag" content="Odin"> 36 37 38 39 40 <link rel="canonical" href="http://jackmordaunt.com/posts/why-people-hate-go/"> 41 42 43 <link rel="preload" href="/fonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin> 44 <link rel="preload" href="/fonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin> 45 <link rel="preload" href="/fonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin> 46 47 48 49 50 <link rel="stylesheet" href="/css/coder.min.6445a802b9389c9660e1b07b724dcf5718b1065ed2d71b4eeaf981cc7cc5fc46.css" integrity="sha256-ZEWoArk4nJZg4bB7ck3PVxixBl7S1xtO6vmBzHzF/EY=" crossorigin="anonymous" media="screen" /> 51 52 53 54 55 56 57 58 59 60 <link rel="stylesheet" href="/css/coder-dark.min.a00e6364bacbc8266ad1cc81230774a1397198f8cfb7bcba29b7d6fcb54ce57f.css" integrity="sha256-oA5jZLrLyCZq0cyBIwd0oTlxmPjPt7y6KbfW/LVM5X8=" crossorigin="anonymous" media="screen" /> 61 62 63 64 65 66 67 68 <link rel="stylesheet" href="/css/custom.min.931a9d02d6f7655cd0cd50317fac1204e00c54ffd0232085acc957b2db5e1283.css" integrity="sha256-kxqdAtb3ZVzQzVAxf6wSBOAMVP/QIyCFrMlXstteEoM=" crossorigin="anonymous" media="screen" /> 69 70 71 72 73 74 75 <link rel="icon" type="image/svg+xml" href="/images/self-tiny-white.svg" sizes="any"> 76 <link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="32x32"> 77 <link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="16x16"> 78 79 <link rel="apple-touch-icon" href="/images/apple-touch-icon.png"> 80 <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png"> 81 82 <link rel="manifest" href="/site.webmanifest"> 83 <link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5"> 84 85 86 87 88 89 90 91 <script defer data-domain="jackmordaunt.com" src="https://plausible.io/js/script.js"></script> 92 93 94 95 96 </head> 97 98 99 100 101 102 103 <body class="preload-transitions colorscheme-auto"> 104 105 <div class="float-container"> 106 <a id="dark-mode-toggle" class="colorscheme-toggle"> 107 <i class="fa-solid fa-adjust fa-fw" aria-hidden="true"></i> 108 </a> 109 </div> 110 111 112 <main class="wrapper"> 113 <nav class="navigation"> 114 <section class="container"> 115 116 <a class="navigation-title" href="http://jackmordaunt.com/"> 117 Jack Mordaunt 118 </a> 119 120 121 <input type="checkbox" id="menu-toggle" /> 122 <label class="menu-button float-right" for="menu-toggle"> 123 <i class="fa-solid fa-bars fa-fw" aria-hidden="true"></i> 124 </label> 125 <ul class="navigation-list"> 126 127 128 <li class="navigation-item"> 129 <a class="navigation-link " href="/posts/">Blog</a> 130 </li> 131 132 <li class="navigation-item"> 133 <a class="navigation-link " href="/about/">About</a> 134 </li> 135 136 <li class="navigation-item"> 137 <a class="navigation-link " href="/projects/">Projects</a> 138 </li> 139 140 <li class="navigation-item"> 141 <a class="navigation-link " href="/contact/">Contact</a> 142 </li> 143 144 <li class="navigation-item"> 145 <a class="navigation-link " href="/pay-with-bitcoin/">Pay</a> 146 </li> 147 148 149 150 </ul> 151 152 </section> 153 </nav> 154 155 156 <div class="content"> 157 158 <section class="container post"> 159 <article> 160 <header> 161 <div class="post-title"> 162 <h1 class="title"> 163 <a class="title-link" href="http://jackmordaunt.com/posts/why-people-hate-go/"> 164 Why People Love to Hate Go 165 </a> 166 </h1> 167 </div> 168 <div class="post-meta"> 169 <div class="date"> 170 <span class="posted-on"> 171 <i class="fa-solid fa-calendar" aria-hidden="true"></i> 172 <time datetime="2025-07-23T14:16:55-03:00"> 173 July 23, 2025 174 </time> 175 </span> 176 <span class="reading-time"> 177 <i class="fa-solid fa-clock" aria-hidden="true"></i> 178 9-minute read 179 </span> 180 </div> 181 <div class="authors"> 182 <i class="fa-solid fa-user" aria-hidden="true"></i> 183 <a href="/authors/jack-mordaunt/">Jack Mordaunt</a></div> 184 185 <div class="categories"> 186 <i class="fa-solid fa-folder" aria-hidden="true"></i> 187 <a href="/categories/development/">Development</a> 188 <span class="separator">•</span> 189 <a href="/categories/opinion/">Opinion</a></div> 190 191 <div class="tags"> 192 <i class="fa-solid fa-tag" aria-hidden="true"></i> 193 <span class="tag"> 194 <a href="/tags/go/">Go</a> 195 </span> 196 <span class="separator">•</span> 197 <span class="tag"> 198 <a href="/tags/odin/">Odin</a> 199 </span></div> 200 201 </div> 202 </header> 203 204 <div class="post-content"> 205 206 <blockquote> 207 <p>Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition.</p></blockquote> 208 <p>In this opinion article I will higlight why I think people love to hate Go.</p> 209 <p>I’ll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the 210 syntax is similar in essence (both heavily inspired by Pascal and C).</p> 211 <p>Unlike Go, Odin actually gives you the good ideas in their completeness - 212 without a complex type system or giving up any control, and without needing to 213 fight the ideas for a decade only to finally concede.</p> 214 <p>This opinion is not a knock against Go authors, or community of which I respect and have 215 been a part for a long time.</p> 216 <p>Modern versions of Go have addressed most of the examples highlighted here. 217 This serves to reinforce the underlying of the article: that these things 218 are valuable, proven by the fact that Go eventually conceded on them.</p> 219 <ul> 220 <li>Go now has generics</li> 221 <li>Go now has iterators</li> 222 <li>Go now has an <code>any</code> alias that is more clear naming than <code>interface{}</code></li> 223 </ul> 224 <p>What follows is not an exhaustive list, but rather just highlights to frame the point being made.</p> 225 <h2 id="generics-for-me-but-not-for-thee"> 226 Generics for Me but Not for Thee 227 <a class="heading-link" href="#generics-for-me-but-not-for-thee"> 228 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 229 <span class="sr-only">Link to heading</span> 230 </a> 231 </h2> 232 <blockquote> 233 <p>Now, time to beat the horse some more.</p></blockquote> 234 <p>Generics: when the relationship <em>between</em> data is the thing you are trying to 235 encode, not the shape of the data itself.</p> 236 <h3 id="go"> 237 Go 238 <a class="heading-link" href="#go"> 239 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 240 <span class="sr-only">Link to heading</span> 241 </a> 242 </h3> 243 <p>For the longest time Go had no user-level generics.</p> 244 <p>It did have generics, but only for the runtime!</p> 245 <p>This is ironic, because it proves the utility of generics while at the very same 246 time denying it to the user.</p> 247 <p>Go has relied heavily on the transpositional nature of data, using one form to represent another. 248 It graces you with the most important structures, which alleviates the problem:</p> 249 <ul> 250 <li>array</li> 251 <li>pointer</li> 252 <li>map</li> 253 <li>slice (dynamic array)</li> 254 <li>channel (thread-safe queue)</li> 255 <li>closure (anonymous function)</li> 256 <li>multiple-returns (pseudo tuple)</li> 257 </ul> 258 <p>In many cases you can rely on what I dub “lexical generics”, function closures that capture 259 lexical values implicitly capture their types as well - making closures highly type-generic 260 in a fascinating way. You will see this be {ab,}used in many Go codebases.</p> 261 <p>Often the friction of custom data structures is high enough that the desired data structure 262 will be transposed onto the runtime data structures.</p> 263 <p>Do you want a queue or stack? Use a slice. 264 Do you want an iterator? Use a channel. 265 Do you want a set or graph? Use a map. 266 Do you want an enum? Use an integer. 267 Do you want a tagged union? Use an integer kind and a fat struct.</p> 268 <p>As you can imagine these choices can come with significant penalties. Using a channel as 269 an iterator, simply because it is both type-generic and integrates with the looping syntax, adds 270 performance overhead due to its thread safety properties. If you don’t need threadsafety, you’re 271 needlessly paying for it anyway, just to coerce the language into being ergonomic to you.</p> 272 <p>It’s not a virtue to rely on the transpositional nature of data structures to avoid generics, 273 but this was the underlying argument for “why do you even need generics?”. 274 The true formulation is more like “we have given you enough generic structures, 275 just transpose onto them”.</p> 276 <p>Go never really told you that generics was not needed, only that it had provided enough already.</p> 277 <h3 id="odin"> 278 Odin 279 <a class="heading-link" href="#odin"> 280 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 281 <span class="sr-only">Link to heading</span> 282 </a> 283 </h3> 284 <p>Odin gives you parametric polymorphism: a simple form of generics that allows for the building of 285 type-safe, generic data structures. It is “simple” because it doesn’t come with a lot of features 286 or baggage. There are no traits, no method sets, and no “complex type system”.</p> 287 <p>Parametric: of parameters. 288 Polymorphism: of many shapes.</p> 289 <p>Put together it means “parameter that can take on many shapes”. The Odin 290 community shortens this to “parapoly” for brevity.</p> 291 <p>When people say they want generics, parapoly is usually what they want.</p> 292 <p>The reality: types are a compile-time-known datum. The idea that you cannot 293 parameterise structures and functions by a simple shape known at compile time 294 is silly. The problem domain: not very complex. This will rhyme when we talk about 295 dynamic types.</p> 296 <p>The punchline: Odin gives you what you actually wanted, parametric polymorphism. 297 It doesn’t expect you to transpose yourself into oblivion.</p> 298 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// A simple structure that cares about the relationship between T's, 299 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// not the shape of T itself. Tell me, where is the complex type-system? 300 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>Node<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span>(<span style="color:#f85149">$</span>T<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">typeid</span>)<span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 301 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>parent<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">^</span>T,<span style="color:#6e7681"> 302 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>child<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">^</span>T,<span style="color:#6e7681"> 303 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> 304 </span></span></span></code></pre></div><h2 id="no-true-dynamic-type"> 305 No True Dynamic Type 306 <a class="heading-link" href="#no-true-dynamic-type"> 307 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 308 <span class="sr-only">Link to heading</span> 309 </a> 310 </h2> 311 <blockquote> 312 <p>Noob: How do I do dynamic typing in Go?</p> 313 <p>Go: Here, use this: <code>interface{}</code> - it’s called the “empty interface”.</p> 314 <p>Noob: …</p> 315 <p>Noob: Uh, what?</p> 316 <p>Go: I wasn’t really meant for dynamic typing, use that or structure your program differently.</p> 317 <p>Noob: Ok fine, I’ll use the “empty interface” then…</p></blockquote> 318 <p>Dynamic programming is important and useful, it’s also not difficult to support first-class.</p> 319 <p>Dynamic types reduce to a fat pointer: a structure that contains two pointers, 320 one pointing to the data and one pointing to the type information. This allows 321 the program to handle arbitrary values at runtime by writing logic against 322 dynamic types.</p> 323 <p>However Go is an OOP language. It encodes the very essence of OOP: behavioural polymorpshim 324 based on v-tables. The term used in Go for this concept is the <code>interface</code>.</p> 325 <p>Like a true dynamic type, the interface is indeed a fat pointer:</p> 326 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#ff7b72">type</span> ITab <span style="color:#ff7b72">struct</span> { 327 </span></span><span style="display:flex;"><span> Inter <span style="color:#ff7b72;font-weight:bold">*</span>InterfaceType 328 </span></span><span style="display:flex;"><span> Type <span style="color:#ff7b72;font-weight:bold">*</span>Type 329 </span></span><span style="display:flex;"><span> <span style="color:#8b949e;font-style:italic">// --snip--</span> 330 </span></span><span style="display:flex;"><span>} 331 </span></span></code></pre></div><p>The revealing part is the separate definition for the empty interface:</p> 332 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#ff7b72">type</span> EmptyInterface <span style="color:#ff7b72">struct</span> { 333 </span></span><span style="display:flex;"><span> Type <span style="color:#ff7b72;font-weight:bold">*</span>Type 334 </span></span><span style="display:flex;"><span> Data unsafe.Pointer 335 </span></span><span style="display:flex;"><span>} 336 </span></span></code></pre></div><p>Why is this bothersome? Instead of just giving you an “any” type, 337 Go forces you to talk in terms of “interfaces that have no methods”.</p> 338 <p>Linguistically and conceptually this makes no sense.</p> 339 <p>This is philosphically impure.</p> 340 <p>Look at these beauties:</p> 341 <ul> 342 <li><code>[]interface{}</code></li> 343 <li><code>map[interface{}]interface{}</code></li> 344 <li><code>func(string, ...interface{})</code></li> 345 <li><code>struct { value interface{} }</code></li> 346 </ul> 347 <p>A better approach is to do what Odin does: just give you the <code>any</code> type. 348 Defined as simple as the concept is, a fat pointer.</p> 349 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Raw_Any points at some data, and associates type data with it. 350 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// This type is named `any` at the user-level. 351 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>Raw_Any<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 352 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>data<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">rawptr</span>,<span style="color:#6e7681"> 353 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>id<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">typeid</span>,<span style="color:#6e7681"> 354 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> 355 </span></span></span></code></pre></div><p>Once you understand fat pointers, dynamic programming becomes easy.</p> 356 <p>Now, if you want an interface in Odin, you simply define a struct that contains 357 a pointer to the data and a pointer to the implementation procedure (rather than 358 a typeid).</p> 359 <p>Consider the common allocator interface:</p> 360 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span>Allocator<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 361 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>procedure<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>Allocator_Proc,<span style="color:#6e7681"> 362 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>data<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">rawptr</span>,<span style="color:#6e7681"> 363 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> 364 </span></span></span></code></pre></div><p>It’s the same underlying idea (with a v-table of 1 to keep it ergonomic).</p> 365 <p>Any specialised allocator just needs to map itself onto this generic Allocator 366 structure and voilà, you have achieved runtime behavioural polymorphism!</p> 367 <p>Go has rectified the language-side of this in later releases, including the 368 <code>any</code> alias (equivalent to <code>interface{}</code> in all ways), but you can see how 369 Go’s design doesn’t reason up from first principles, but rather down from empiricism.</p> 370 <blockquote> 371 <p>We think objects are good idea.</p> 372 <p>We want to do them at runtime.</p> 373 <p>Aha, the interface type. It’s a fat pointer to a vtable and some data.</p> 374 <p>Look, if you want to do dynamic programming you can just use an empty interface!</p></blockquote> 375 <h2 id="declaration-and-assignment-syntax"> 376 Declaration and Assignment Syntax 377 <a class="heading-link" href="#declaration-and-assignment-syntax"> 378 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 379 <span class="sr-only">Link to heading</span> 380 </a> 381 </h2> 382 <p>Go and Odin both use this Pascal inspired declaration-assignment syntax <code>:=</code>.</p> 383 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Go</span> 384 </span></span><span style="display:flex;"><span> 385 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">var</span> variable <span style="color:#ff7b72">string</span> = <span style="color:#a5d6ff">"variable"</span> 386 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">var</span> variable = <span style="color:#a5d6ff">"variable"</span> 387 </span></span><span style="display:flex;"><span> 388 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> constant <span style="color:#ff7b72">string</span> = <span style="color:#a5d6ff">"constant"</span> 389 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> constant = <span style="color:#a5d6ff">"constant"</span> 390 </span></span><span style="display:flex;"><span> 391 </span></span><span style="display:flex;"><span>x <span style="color:#ff7b72;font-weight:bold">:=</span> <span style="color:#a5d6ff">"foobar"</span> 392 </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Odin 393 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> 394 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>variable<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:=</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">"variable"</span><span style="color:#6e7681"> 395 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>variable<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">string</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">"variable"</span><span style="color:#6e7681"> 396 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 397 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>constant<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">"constant"</span><span style="color:#6e7681"> 398 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>constant<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">string</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">"constant"</span><span style="color:#6e7681"> 399 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 400 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>x<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:=</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">"foobar"</span><span style="color:#6e7681"> 401 </span></span></span></code></pre></div><p>What’s the problem? Well, the thing is that Go defines <code>:=</code> as a keyword. 402 You cannot actually place a type between <code>:</code> and <code>=</code>.</p> 403 <p>Once again Go fails to give you the complete idea, the grammar: <code><symbol> : <type> = <expression></code>. 404 Where the type can be elided to result in <code><symbol> := <expression></code>. 405 Where constants are the same, but with a second <code>:</code> instead of <code>=</code>.</p> 406 <p>Go has chosen an inconsistent approach. When the underlying grammar is elegant, 407 Go decides to take the shortcut and ignore the point. Odin just gives you the 408 elegant, consistent grammar.</p> 409 <p>Consider type and proc definitions:</p> 410 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Go</span> 411 </span></span><span style="display:flex;"><span> 412 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">type</span> Node <span style="color:#ff7b72">struct</span> { 413 </span></span><span style="display:flex;"><span> <span style="color:#8b949e;font-style:italic">// --snip--</span> 414 </span></span><span style="display:flex;"><span>} 415 </span></span><span style="display:flex;"><span> 416 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">func</span> <span style="color:#d2a8ff;font-weight:bold">Visit</span>(n Node) { 417 </span></span><span style="display:flex;"><span> <span style="color:#8b949e;font-style:italic">// --snip</span> 418 </span></span><span style="display:flex;"><span>} 419 </span></span></code></pre></div><p>In the Go syntax we have introduced more keywords to declare types and 420 functions. Why do we need extra syntax here? After all, struct and function 421 definitions are just regular constants!</p> 422 <p>In Odin, this fact is evident.</p> 423 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Odin 424 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> 425 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>node<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 426 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- 427 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> 428 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 429 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>visit<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(n<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>node)<span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 430 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- 431 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> 432 </span></span></span></code></pre></div><p>The syntax is consistent:</p> 433 <ul> 434 <li>consistent with other constants</li> 435 <li>consistently read left-to-right, with symbol first, type second, and finally the binding third</li> 436 </ul> 437 <p>After all, a struct defintion is a compile-time known value. 438 Thus, the <code>node</code> type is just regular constant set to a typeid.</p> 439 <p>Don’t believe me? Check this out:</p> 440 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Odin 441 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> 442 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>node<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{}<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 443 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- 444 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> 445 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 446 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>visit<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(n<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>node)<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(n<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>node)<span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 447 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- 448 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> 449 </span></span></span></code></pre></div><p>You <em>can</em> put the type in the normal type position, it’s just elided by convention!</p> 450 <p>And if you want them to be variables instead:</p> 451 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Odin 452 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> 453 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>node<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{}<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 454 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- 455 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> 456 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 457 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>visit<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(n<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>node)<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(n<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>node)<span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 458 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- 459 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> 460 </span></span></span></code></pre></div><p>Odin takes the underlying idea of elegant, minimal and consistent grammar and 461 actually just hands it to you. Type definitions are <em>just</em> constants!</p> 462 <p>Go decides to keep the shorthand <code>:=</code> but never actually fully embraces the 463 underlying idea. You can’t put a type between <code>:</code> and <code>=</code>, and you are expected 464 to use bespoke keywords for type and function declarations.</p> 465 <p>Feel the inconsistency.</p> 466 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Go</span> 467 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> c <span style="color:#ff7b72">int</span> = <span style="color:#a5d6ff">42</span> 468 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> c = <span style="color:#a5d6ff">42</span> 469 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">var</span> v <span style="color:#ff7b72">int</span> = <span style="color:#a5d6ff">42</span> 470 </span></span><span style="display:flex;"><span><span style="color:#ff7b72">var</span> v = <span style="color:#a5d6ff">42</span> 471 </span></span><span style="display:flex;"><span>v <span style="color:#ff7b72;font-weight:bold">:=</span> <span style="color:#a5d6ff">42</span> 472 </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// Odin 473 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>c<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">int</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>42<span style="color:#6e7681"> 474 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>c<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span>42<span style="color:#6e7681"> 475 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>v<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">int</span><span style="color:#6e7681"> 476 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>v<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">int</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span>42<span style="color:#6e7681"> 477 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>v<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:=</span><span style="color:#6e7681"> </span>42<span style="color:#6e7681"> 478 </span></span></span></code></pre></div><h2 id="conclusion"> 479 Conclusion 480 <a class="heading-link" href="#conclusion"> 481 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 482 <span class="sr-only">Link to heading</span> 483 </a> 484 </h2> 485 <p>Go develops features empirically, adopting what works practically. Odin constructs from first principles, focusing on conceptual elegance.</p> 486 <p>Go’s incremental evolution led to ad-hoc syntax and features, making it feel less coherent to users accustomed to functional or fully featured OOP languages.</p> 487 <p>Conversely, Odin feels purposeful and coherent, designed from foundational ideas rather than incremental adaptations.</p> 488 <p>Despite these criticisms, Go remains practical and solid, which explains its continued popularity—and why many developers both love and hate it.</p> 489 490 </div> 491 492 493 <footer> 494 495 496 497 498 499 500 501 502 503 504 </footer> 505 </article> 506 507 508 </section> 509 510 </div> 511 512 <footer class="footer"> 513 <section class="container"> 514 © 515 516 2025 517 Jack Mordaunt 518 · 519 520 Powered by <a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo</a> & <a href="https://github.com/luizdepra/hugo-coder/" target="_blank" rel="noopener">Coder</a>. 521 522 </section> 523 </footer> 524 525 </main> 526 527 528 529 530 531 <script src="/js/coder.min.6ae284be93d2d19dad1f02b0039508d9aab3180a12a06dcc71b0b0ef7825a317.js" integrity="sha256-auKEvpPS0Z2tHwKwA5UI2aqzGAoSoG3McbCw73gloxc="></script> 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 </body> 573 </html>