commit 938da080c6bd7204c85d2d4eb78e412b1ded64c1 parent 0be756c6187d2a0a8cc5c1add6cea7fb7067e090 Author: Jack Mordaunt <jackmordaunt.dev@gmail.com> Date: Sun, 27 Jul 2025 14:50:12 -0300 site: add article "why people hate go" Signed-off-by: Jack Mordaunt <jackmordaunt.dev@gmail.com> Diffstat:
23 files changed, 1591 insertions(+), 33 deletions(-)
diff --git a/content/posts/why-people-hate-go.md b/content/posts/why-people-hate-go.md @@ -0,0 +1,364 @@ ++++ +draft = false +date = 2025-07-23T14:16:55-03:00 +title = "Why People Love to Hate Go" +description = "Go has good ideas but never gives them to you completely." +slug = "" +authors = ["Jack Mordaunt"] +tags = ["Go", "Odin"] +categories = ["development", "opinion"] +externalLink = "" +series = [] ++++ + +> Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition. + +In this opinion article I will higlight why I think people love to hate Go. + +I'll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the +syntax is similar in essence (both heavily inspired by Pascal and C). + +Unlike Go, Odin actually gives you the good ideas in their completeness - +without a complex type system or giving up any control, and without needing to +fight the ideas for a decade only to finally concede. + +This opinion is not a knock against Go authors, or community of which I respect and have +been a part for a long time. + +Modern versions of Go have addressed most of the examples highlighted here. +This serves to reinforce the underlying of the article: that these things +are valuable, proven by the fact that Go eventually conceded on them. + +- Go now has generics +- Go now has iterators +- Go now has an `any` alias that is more clear naming than `interface{}` + +What follows is not an exhaustive list, but rather just highlights to frame the point being made. + +## Generics for Me but Not for Thee + +> Now, time to beat the horse some more. + +Generics: when the relationship _between_ data is the thing you are trying to +encode, not the shape of the data itself. + +### Go + +For the longest time Go had no user-level generics. + +It did have generics, but only for the runtime! + +This is ironic, because it proves the utility of generics while at the very same +time denying it to the user. + +Go has relied heavily on the transpositional nature of data, using one form to represent another. +It graces you with the most important structures, which alleviates the problem: + +- array +- pointer +- map +- slice (dynamic array) +- channel (thread-safe queue) +- closure (anonymous function) +- multiple-returns (pseudo tuple) + +In many cases you can rely on what I dub "lexical generics", function closures that capture +lexical values implicitly capture their types as well - making closures highly type-generic +in a fascinating way. You will see this be {ab,}used in many Go codebases. + +Often the friction of custom data structures is high enough that the desired data structure +will be transposed onto the runtime data structures. + +Do you want a queue or stack? Use a slice. +Do you want an iterator? Use a channel. +Do you want a set or graph? Use a map. +Do you want an enum? Use an integer. +Do you want a tagged union? Use an integer kind and a fat struct. + +As you can imagine these choices can come with significant penalties. Using a channel as +an iterator, simply because it is both type-generic and integrates with the looping syntax, adds +performance overhead due to its thread safety properties. If you don't need threadsafety, you're +needlessly paying for it anyway, just to coerce the language into being ergonomic to you. + +It's not a virtue to rely on the transpositional nature of data structures to avoid generics, +but this was the underlying argument for "why do you even need generics?". +The true formulation is more like "we have given you enough generic structures, +just transpose onto them". + +Go never really told you that generics was not needed, only that it had provided enough already. + +### Odin + +Odin gives you parametric polymorphism: a simple form of generics that allows for the building of +type-safe, generic data structures. It is "simple" because it doesn't come with a lot of features +or baggage. There are no traits, no method sets, and no "complex type system". + +Parametric: of parameters. +Polymorphism: of many shapes. + +Put together it means "parameter that can take on many shapes". The Odin +community shortens this to "parapoly" for brevity. + +When people say they want generics, parapoly is usually what they want. + +The reality: types are a compile-time-known datum. The idea that you cannot +parameterise structures and functions by a simple shape known at compile time +is silly. The problem domain: not very complex. This will rhyme when we talk about +dynamic types. + +The punchline: Odin gives you what you actually wanted, parametric polymorphism. +It doesn't expect you to transpose yourself into oblivion. + +```odin +// A simple structure that cares about the relationship between T's, +// not the shape of T itself. Tell me, where is the complex type-system? +Node :: struct($T: typeid) { + parent: ^T, + child: ^T, +} +``` + +## No True Dynamic Type + +> Noob: How do I do dynamic typing in Go? +> +> Go: Here, use this: `interface{}` - it's called the "empty interface". +> +> Noob: ... +> +> Noob: Uh, what? +> +> Go: I wasn't really meant for dynamic typing, use that or structure your program differently. +> +> Noob: Ok fine, I'll use the "empty interface" then... +> + +Dynamic programming is important and useful, it's also not difficult to support first-class. + +Dynamic types reduce to a fat pointer: a structure that contains two pointers, +one pointing to the data and one pointing to the type information. This allows +the program to handle arbitrary values at runtime by writing logic against +dynamic types. + +However Go is an OOP language. It encodes the very essence of OOP: behavioural polymorpshim +based on v-tables. The term used in Go for this concept is the `interface`. + +Like a true dynamic type, the interface is indeed a fat pointer: + +```go +type ITab struct { + Inter *InterfaceType + Type *Type + // --snip-- +} +``` +The revealing part is the separate definition for the empty interface: + +```go +type EmptyInterface struct { + Type *Type + Data unsafe.Pointer +} +``` + +Why is this bothersome? Instead of just giving you an "any" type, +Go forces you to talk in terms of "interfaces that have no methods". + +Linguistically and conceptually this makes no sense. + +This is philosphically impure. + +Look at these beauties: +- `[]interface{}` +- `map[interface{}]interface{}` +- `func(string, ...interface{})` +- `struct { value interface{} }` + +A better approach is to do what Odin does: just give you the `any` type. +Defined as simple as the concept is, a fat pointer. + +```odin +// Raw_Any points at some data, and associates type data with it. +// This type is named `any` at the user-level. +Raw_Any :: struct { + data: rawptr, + id: typeid, +} +``` + +Once you understand fat pointers, dynamic programming becomes easy. + +Now, if you want an interface in Odin, you simply define a struct that contains +a pointer to the data and a pointer to the implementation procedure (rather than +a typeid). + +Consider the common allocator interface: + +```odin +Allocator :: struct { + procedure: Allocator_Proc, + data: rawptr, +} +``` + +It's the same underlying idea (with a v-table of 1 to keep it ergonomic). + +Any specialised allocator just needs to map itself onto this generic Allocator +structure and voilà, you have achieved runtime behavioural polymorphism! + +Go has rectified the language-side of this in later releases, including the +`any` alias (equivalent to `interface{}` in all ways), but you can see how +Go's design doesn't reason up from first principles, but rather down from empiricism. + +> We think objects are good idea. +> +> We want to do them at runtime. +> +> Aha, the interface type. It's a fat pointer to a vtable and some data. +> +> Look, if you want to do dynamic programming you can just use an empty interface! +> + +## Declaration and Assignment Syntax + +Go and Odin both use this Pascal inspired declaration-assignment syntax `:=`. + +```go +// Go + +var variable string = "variable" +var variable = "variable" + +const constant string = "constant" +const constant = "constant" + +x := "foobar" +``` + +```odin +// Odin + +variable := "variable" +variable: string = "variable" + +constant :: "constant" +constant: string : "constant" + +x := "foobar" +``` + +What's the problem? Well, the thing is that Go defines `:=` as a keyword. +You cannot actually place a type between `:` and `=`. + +Once again Go fails to give you the complete idea, the grammar: `<symbol> : <type> = <expression>`. +Where the type can be elided to result in `<symbol> := <expression>`. +Where constants are the same, but with a second `:` instead of `=`. + +Go has chosen an inconsistent approach. When the underlying grammar is elegant, +Go decides to take the shortcut and ignore the point. Odin just gives you the +elegant, consistent grammar. + +Consider type and proc definitions: + +```go +// Go + +type Node struct { + // --snip-- +} + +func Visit(n Node) { + // --snip +} +``` + +In the Go syntax we have introduced more keywords to declare types and +functions. Why do we need extra syntax here? After all, struct and function +definitions are just regular constants! + +In Odin, this fact is evident. + +```odin +// Odin + +node :: struct { + // --snip-- +} + +visit :: proc(n: node) { + // --snip-- +} +``` + +The syntax is consistent: +- consistent with other constants +- consistently read left-to-right, with symbol first, type second, and finally the binding third + +After all, a struct defintion is a compile-time known value. +Thus, the `node` type is just regular constant set to a typeid. + +Don't believe me? Check this out: + +```odin +// Odin + +node: struct {} : struct { + // --snip-- +} + +visit: proc(n: node) : proc(n: node) { + // --snip-- +} +``` + +You _can_ put the type in the normal type position, it's just elided by convention! + +And if you want them to be variables instead: + +```odin +// Odin + +node: struct {} = struct { + // --snip-- +} + +visit: proc(n: node) = proc(n: node) { + // --snip-- +} +``` + +Odin takes the underlying idea of elegant, minimal and consistent grammar and +actually just hands it to you. Type definitions are _just_ constants! + +Go decides to keep the shorthand `:=` but never actually fully embraces the +underlying idea. You can't put a type between `:` and `=`, and you are expected +to use bespoke keywords for type and function declarations. + +Feel the inconsistency. + +```go +// Go +const c int = 42 +const c = 42 +var v int = 42 +var v = 42 +v := 42 +``` + +```odin +// Odin +c: int : 42 +c :: 42 +v: int +v: int = 42 +v := 42 +``` + +## Conclusion +Go develops features empirically, adopting what works practically. Odin constructs from first principles, focusing on conceptual elegance. + +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. + +Conversely, Odin feels purposeful and coherent, designed from foundational ideas rather than incremental adaptations. + +Despite these criticisms, Go remains practical and solid, which explains its continued popularity—and why many developers both love and hate it. diff --git a/public/authors/index.html b/public/authors/index.html @@ -162,7 +162,7 @@ <li> <span class="taxonomy-element"> <a href="http://jackmordaunt.com/authors/jack-mordaunt/">Jack Mordaunt</a> - <sup>4</sup> + <sup>5</sup> </span> </li> diff --git a/public/authors/index.xml b/public/authors/index.xml @@ -6,12 +6,12 @@ <description>Recent content in Authors on Jack Mordaunt</description> <generator>Hugo</generator> <language>en</language> - <lastBuildDate>Thu, 17 Jul 2025 11:21:04 -0300</lastBuildDate> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> <atom:link href="http://jackmordaunt.com/authors/index.xml" rel="self" type="application/rss+xml" /> <item> <title>Jack Mordaunt</title> <link>http://jackmordaunt.com/authors/jack-mordaunt/</link> - <pubDate>Thu, 17 Jul 2025 11:21:04 -0300</pubDate> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> <guid>http://jackmordaunt.com/authors/jack-mordaunt/</guid> <description></description> </item> diff --git a/public/authors/jack-mordaunt/index.html b/public/authors/jack-mordaunt/index.html @@ -156,6 +156,11 @@ <ul> <li> + <span class="date">July 23, 2025</span> + <a class="title" href="/posts/why-people-hate-go/">Why People Love to Hate Go</a> + </li> + + <li> <span class="date">July 17, 2025</span> <a class="title" href="/projects/plato-desktop-client/">Plato Desktop Client</a> </li> diff --git a/public/authors/jack-mordaunt/index.xml b/public/authors/jack-mordaunt/index.xml @@ -6,9 +6,16 @@ <description>Recent content on Jack Mordaunt</description> <generator>Hugo</generator> <language>en</language> - <lastBuildDate>Thu, 17 Jul 2025 11:21:04 -0300</lastBuildDate> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> <atom:link href="http://jackmordaunt.com/authors/jack-mordaunt/index.xml" rel="self" type="application/rss+xml" /> <item> + <title>Why People Love to Hate Go</title> + <link>http://jackmordaunt.com/posts/why-people-hate-go/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/posts/why-people-hate-go/</guid> + <description><blockquote>
<p>Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition.</p></blockquote>
<p>In this opinion article I will higlight why I think people love to hate Go.</p>
<p>I&rsquo;ll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the
syntax is similar in essence (both heavily inspired by Pascal and C).</p>
<p>Unlike Go, Odin actually gives you the good ideas in their completeness -
without a complex type system or giving up any control, and without needing to
fight the ideas for a decade only to finally concede.</p></description> + </item> + <item> <title>Plato Desktop Client</title> <link>http://jackmordaunt.com/projects/plato-desktop-client/</link> <pubDate>Thu, 17 Jul 2025 11:21:04 -0300</pubDate> diff --git a/public/categories/development/index.html b/public/categories/development/index.html @@ -156,6 +156,11 @@ <ul> <li> + <span class="date">July 23, 2025</span> + <a class="title" href="/posts/why-people-hate-go/">Why People Love to Hate Go</a> + </li> + + <li> <span class="date">July 17, 2025</span> <a class="title" href="/projects/plato-desktop-client/">Plato Desktop Client</a> </li> diff --git a/public/categories/development/index.xml b/public/categories/development/index.xml @@ -6,9 +6,16 @@ <description>Recent content in Development on Jack Mordaunt</description> <generator>Hugo</generator> <language>en</language> - <lastBuildDate>Thu, 17 Jul 2025 11:21:04 -0300</lastBuildDate> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> <atom:link href="http://jackmordaunt.com/categories/development/index.xml" rel="self" type="application/rss+xml" /> <item> + <title>Why People Love to Hate Go</title> + <link>http://jackmordaunt.com/posts/why-people-hate-go/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/posts/why-people-hate-go/</guid> + <description><blockquote>
<p>Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition.</p></blockquote>
<p>In this opinion article I will higlight why I think people love to hate Go.</p>
<p>I&rsquo;ll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the
syntax is similar in essence (both heavily inspired by Pascal and C).</p>
<p>Unlike Go, Odin actually gives you the good ideas in their completeness -
without a complex type system or giving up any control, and without needing to
fight the ideas for a decade only to finally concede.</p></description> + </item> + <item> <title>Plato Desktop Client</title> <link>http://jackmordaunt.com/projects/plato-desktop-client/</link> <pubDate>Thu, 17 Jul 2025 11:21:04 -0300</pubDate> diff --git a/public/categories/index.html b/public/categories/index.html @@ -162,7 +162,18 @@ <li> <span class="taxonomy-element"> <a href="http://jackmordaunt.com/categories/development/">development</a> - <sup>5</sup> + <sup>6</sup> + </span> + </li> + + + + + + <li> + <span class="taxonomy-element"> + <a href="http://jackmordaunt.com/categories/opinion/">opinion</a> + <sup>1</sup> </span> </li> diff --git a/public/categories/index.xml b/public/categories/index.xml @@ -6,14 +6,21 @@ <description>Recent content in Categories on Jack Mordaunt</description> <generator>Hugo</generator> <language>en</language> - <lastBuildDate>Thu, 17 Jul 2025 11:21:04 -0300</lastBuildDate> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> <atom:link href="http://jackmordaunt.com/categories/index.xml" rel="self" type="application/rss+xml" /> <item> <title>Development</title> <link>http://jackmordaunt.com/categories/development/</link> - <pubDate>Thu, 17 Jul 2025 11:21:04 -0300</pubDate> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> <guid>http://jackmordaunt.com/categories/development/</guid> <description></description> </item> + <item> + <title>Opinion</title> + <link>http://jackmordaunt.com/categories/opinion/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/categories/opinion/</guid> + <description></description> + </item> </channel> </rss> diff --git a/public/categories/opinion/index.html b/public/categories/opinion/index.html @@ -0,0 +1,237 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <title>Category: Opinion · Jack Mordaunt</title> + <meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<meta name="color-scheme" content="light dark"> + + + + +<meta name="author" content="Jack Mordaunt"> +<meta name="description" content="Coffee developer, software brewer."> +<meta name="keywords" content="blog,developer,personal,software,robust,performance,sovereign"> + + + + <meta name="twitter:card" content="summary"> + <meta name="twitter:title" content="Opinion"> + <meta name="twitter:description" content="Coffee developer, software brewer."> + +<meta property="og:url" content="http://jackmordaunt.com/categories/opinion/"> + <meta property="og:site_name" content="Jack Mordaunt"> + <meta property="og:title" content="Opinion"> + <meta property="og:description" content="Coffee developer, software brewer."> + <meta property="og:locale" content="en"> + <meta property="og:type" content="website"> + + + + +<link rel="canonical" href="http://jackmordaunt.com/categories/opinion/"> + + +<link rel="preload" href="/fonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin> +<link rel="preload" href="/fonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin> +<link rel="preload" href="/fonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin> + + + + + <link rel="stylesheet" href="/css/coder.min.6445a802b9389c9660e1b07b724dcf5718b1065ed2d71b4eeaf981cc7cc5fc46.css" integrity="sha256-ZEWoArk4nJZg4bB7ck3PVxixBl7S1xtO6vmBzHzF/EY=" crossorigin="anonymous" media="screen" /> + + + + + + + + + + <link rel="stylesheet" href="/css/coder-dark.min.a00e6364bacbc8266ad1cc81230774a1397198f8cfb7bcba29b7d6fcb54ce57f.css" integrity="sha256-oA5jZLrLyCZq0cyBIwd0oTlxmPjPt7y6KbfW/LVM5X8=" crossorigin="anonymous" media="screen" /> + + + + + + + + <link rel="stylesheet" href="/css/custom.min.931a9d02d6f7655cd0cd50317fac1204e00c54ffd0232085acc957b2db5e1283.css" integrity="sha256-kxqdAtb3ZVzQzVAxf6wSBOAMVP/QIyCFrMlXstteEoM=" crossorigin="anonymous" media="screen" /> + + + + + + +<link rel="icon" type="image/svg+xml" href="/images/self-tiny-white.svg" sizes="any"> +<link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="32x32"> +<link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="16x16"> + +<link rel="apple-touch-icon" href="/images/apple-touch-icon.png"> +<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png"> + +<link rel="manifest" href="/site.webmanifest"> +<link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5"> + + +<link rel="alternate" type="application/rss+xml" href="/categories/opinion/index.xml" title="Jack Mordaunt" /> + + + + + + + +</head> + + + + + + +<body class="preload-transitions colorscheme-auto"> + +<div class="float-container"> + <a id="dark-mode-toggle" class="colorscheme-toggle"> + <i class="fa-solid fa-adjust fa-fw" aria-hidden="true"></i> + </a> +</div> + + + <main class="wrapper"> + <nav class="navigation"> + <section class="container"> + + <a class="navigation-title" href="http://jackmordaunt.com/"> + Jack Mordaunt + </a> + + + <input type="checkbox" id="menu-toggle" /> + <label class="menu-button float-right" for="menu-toggle"> + <i class="fa-solid fa-bars fa-fw" aria-hidden="true"></i> + </label> + <ul class="navigation-list"> + + + <li class="navigation-item"> + <a class="navigation-link " href="/posts/">Blog</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/about/">About</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/projects/">Projects</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/contact/">Contact</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/pay-with-bitcoin/">Pay</a> + </li> + + + + </ul> + + </section> +</nav> + + + <div class="content"> + + <section class="container list"> + <header> + <h1 class="title"> + <a class="title-link" href="http://jackmordaunt.com/categories/opinion/">Category: Opinion</a> + </h1> + </header> + + <ul> + + <li> + <span class="date">July 23, 2025</span> + <a class="title" href="/posts/why-people-hate-go/">Why People Love to Hate Go</a> + </li> + + </ul> + + + + + + + +</section> + + + </div> + + <footer class="footer"> + <section class="container"> + © + + 2025 + Jack Mordaunt + · + + 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>. + + </section> +</footer> + + </main> + + + + + + <script src="/js/coder.min.6ae284be93d2d19dad1f02b0039508d9aab3180a12a06dcc71b0b0ef7825a317.js" integrity="sha256-auKEvpPS0Z2tHwKwA5UI2aqzGAoSoG3McbCw73gloxc="></script> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +</body> +</html> diff --git a/public/categories/opinion/index.xml b/public/categories/opinion/index.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> + <channel> + <title>Opinion on Jack Mordaunt</title> + <link>http://jackmordaunt.com/categories/opinion/</link> + <description>Recent content in Opinion on Jack Mordaunt</description> + <generator>Hugo</generator> + <language>en</language> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> + <atom:link href="http://jackmordaunt.com/categories/opinion/index.xml" rel="self" type="application/rss+xml" /> + <item> + <title>Why People Love to Hate Go</title> + <link>http://jackmordaunt.com/posts/why-people-hate-go/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/posts/why-people-hate-go/</guid> + <description><blockquote>
<p>Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition.</p></blockquote>
<p>In this opinion article I will higlight why I think people love to hate Go.</p>
<p>I&rsquo;ll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the
syntax is similar in essence (both heavily inspired by Pascal and C).</p>
<p>Unlike Go, Odin actually gives you the good ideas in their completeness -
without a complex type system or giving up any control, and without needing to
fight the ideas for a decade only to finally concede.</p></description> + </item> + </channel> +</rss> diff --git a/public/categories/opinion/page/1/index.html b/public/categories/opinion/page/1/index.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <title>http://jackmordaunt.com/categories/opinion/</title> + <link rel="canonical" href="http://jackmordaunt.com/categories/opinion/"> + <meta name="robots" content="noindex"> + <meta charset="utf-8"> + <meta http-equiv="refresh" content="0; url=http://jackmordaunt.com/categories/opinion/"> + </head> +</html> diff --git a/public/posts/index.html b/public/posts/index.html @@ -158,6 +158,10 @@ </header> <ul><li> + <span class="date">July 23, 2025</span> + <a class="title" href="/posts/why-people-hate-go/">Why People Love to Hate Go</a> +</li> +<li> <span class="date">July 16, 2025</span> <a class="title" href="/posts/hugo-nip-05/">Hugo and nip-05</a> </li> diff --git a/public/posts/index.xml b/public/posts/index.xml @@ -6,9 +6,16 @@ <description>Recent content in Posts on Jack Mordaunt</description> <generator>Hugo</generator> <language>en</language> - <lastBuildDate>Wed, 16 Jul 2025 14:57:56 -0300</lastBuildDate> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> <atom:link href="http://jackmordaunt.com/posts/index.xml" rel="self" type="application/rss+xml" /> <item> + <title>Why People Love to Hate Go</title> + <link>http://jackmordaunt.com/posts/why-people-hate-go/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/posts/why-people-hate-go/</guid> + <description><blockquote>
<p>Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition.</p></blockquote>
<p>In this opinion article I will higlight why I think people love to hate Go.</p>
<p>I&rsquo;ll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the
syntax is similar in essence (both heavily inspired by Pascal and C).</p>
<p>Unlike Go, Odin actually gives you the good ideas in their completeness -
without a complex type system or giving up any control, and without needing to
fight the ideas for a decade only to finally concede.</p></description> + </item> + <item> <title>Hugo and nip-05</title> <link>http://jackmordaunt.com/posts/hugo-nip-05/</link> <pubDate>Wed, 16 Jul 2025 14:57:56 -0300</pubDate> diff --git a/public/posts/why-people-hate-go/index.html b/public/posts/why-people-hate-go/index.html @@ -0,0 +1,570 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <title> + Why People Love to Hate Go · Jack Mordaunt +</title> + <meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<meta name="color-scheme" content="light dark"> + + + + +<meta name="author" content="Jack Mordaunt"> +<meta name="description" content="Go has good ideas but never gives them to you completely."> +<meta name="keywords" content="blog,developer,personal,software,robust,performance,sovereign"> + + + + <meta name="twitter:card" content="summary"> + <meta name="twitter:title" content="Why People Love to Hate Go"> + <meta name="twitter:description" content="Go has good ideas but never gives them to you completely."> + +<meta property="og:url" content="http://jackmordaunt.com/posts/why-people-hate-go/"> + <meta property="og:site_name" content="Jack Mordaunt"> + <meta property="og:title" content="Why People Love to Hate Go"> + <meta property="og:description" content="Go has good ideas but never gives them to you completely."> + <meta property="og:locale" content="en"> + <meta property="og:type" content="article"> + <meta property="article:section" content="posts"> + <meta property="article:published_time" content="2025-07-23T14:16:55-03:00"> + <meta property="article:modified_time" content="2025-07-23T14:16:55-03:00"> + <meta property="article:tag" content="Go"> + <meta property="article:tag" content="Odin"> + + + + +<link rel="canonical" href="http://jackmordaunt.com/posts/why-people-hate-go/"> + + +<link rel="preload" href="/fonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin> +<link rel="preload" href="/fonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin> +<link rel="preload" href="/fonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin> + + + + + <link rel="stylesheet" href="/css/coder.min.6445a802b9389c9660e1b07b724dcf5718b1065ed2d71b4eeaf981cc7cc5fc46.css" integrity="sha256-ZEWoArk4nJZg4bB7ck3PVxixBl7S1xtO6vmBzHzF/EY=" crossorigin="anonymous" media="screen" /> + + + + + + + + + + <link rel="stylesheet" href="/css/coder-dark.min.a00e6364bacbc8266ad1cc81230774a1397198f8cfb7bcba29b7d6fcb54ce57f.css" integrity="sha256-oA5jZLrLyCZq0cyBIwd0oTlxmPjPt7y6KbfW/LVM5X8=" crossorigin="anonymous" media="screen" /> + + + + + + + + <link rel="stylesheet" href="/css/custom.min.931a9d02d6f7655cd0cd50317fac1204e00c54ffd0232085acc957b2db5e1283.css" integrity="sha256-kxqdAtb3ZVzQzVAxf6wSBOAMVP/QIyCFrMlXstteEoM=" crossorigin="anonymous" media="screen" /> + + + + + + +<link rel="icon" type="image/svg+xml" href="/images/self-tiny-white.svg" sizes="any"> +<link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="32x32"> +<link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="16x16"> + +<link rel="apple-touch-icon" href="/images/apple-touch-icon.png"> +<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png"> + +<link rel="manifest" href="/site.webmanifest"> +<link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5"> + + + + + + + + + +</head> + + + + + + +<body class="preload-transitions colorscheme-auto"> + +<div class="float-container"> + <a id="dark-mode-toggle" class="colorscheme-toggle"> + <i class="fa-solid fa-adjust fa-fw" aria-hidden="true"></i> + </a> +</div> + + + <main class="wrapper"> + <nav class="navigation"> + <section class="container"> + + <a class="navigation-title" href="http://jackmordaunt.com/"> + Jack Mordaunt + </a> + + + <input type="checkbox" id="menu-toggle" /> + <label class="menu-button float-right" for="menu-toggle"> + <i class="fa-solid fa-bars fa-fw" aria-hidden="true"></i> + </label> + <ul class="navigation-list"> + + + <li class="navigation-item"> + <a class="navigation-link " href="/posts/">Blog</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/about/">About</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/projects/">Projects</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/contact/">Contact</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/pay-with-bitcoin/">Pay</a> + </li> + + + + </ul> + + </section> +</nav> + + + <div class="content"> + + <section class="container post"> + <article> + <header> + <div class="post-title"> + <h1 class="title"> + <a class="title-link" href="http://jackmordaunt.com/posts/why-people-hate-go/"> + Why People Love to Hate Go + </a> + </h1> + </div> + <div class="post-meta"> + <div class="date"> + <span class="posted-on"> + <i class="fa-solid fa-calendar" aria-hidden="true"></i> + <time datetime="2025-07-23T14:16:55-03:00"> + July 23, 2025 + </time> + </span> + <span class="reading-time"> + <i class="fa-solid fa-clock" aria-hidden="true"></i> + 9-minute read + </span> + </div> + <div class="authors"> + <i class="fa-solid fa-user" aria-hidden="true"></i> + <a href="/authors/jack-mordaunt/">Jack Mordaunt</a></div> + + <div class="categories"> + <i class="fa-solid fa-folder" aria-hidden="true"></i> + <a href="/categories/development/">Development</a> + <span class="separator">•</span> + <a href="/categories/opinion/">Opinion</a></div> + + <div class="tags"> + <i class="fa-solid fa-tag" aria-hidden="true"></i> + <span class="tag"> + <a href="/tags/go/">Go</a> + </span> + <span class="separator">•</span> + <span class="tag"> + <a href="/tags/odin/">Odin</a> + </span></div> + + </div> + </header> + + <div class="post-content"> + + <blockquote> +<p>Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition.</p></blockquote> +<p>In this opinion article I will higlight why I think people love to hate Go.</p> +<p>I’ll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the +syntax is similar in essence (both heavily inspired by Pascal and C).</p> +<p>Unlike Go, Odin actually gives you the good ideas in their completeness - +without a complex type system or giving up any control, and without needing to +fight the ideas for a decade only to finally concede.</p> +<p>This opinion is not a knock against Go authors, or community of which I respect and have +been a part for a long time.</p> +<p>Modern versions of Go have addressed most of the examples highlighted here. +This serves to reinforce the underlying of the article: that these things +are valuable, proven by the fact that Go eventually conceded on them.</p> +<ul> +<li>Go now has generics</li> +<li>Go now has iterators</li> +<li>Go now has an <code>any</code> alias that is more clear naming than <code>interface{}</code></li> +</ul> +<p>What follows is not an exhaustive list, but rather just highlights to frame the point being made.</p> +<h2 id="generics-for-me-but-not-for-thee"> + Generics for Me but Not for Thee + <a class="heading-link" href="#generics-for-me-but-not-for-thee"> + <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> + <span class="sr-only">Link to heading</span> + </a> +</h2> +<blockquote> +<p>Now, time to beat the horse some more.</p></blockquote> +<p>Generics: when the relationship <em>between</em> data is the thing you are trying to +encode, not the shape of the data itself.</p> +<h3 id="go"> + Go + <a class="heading-link" href="#go"> + <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> + <span class="sr-only">Link to heading</span> + </a> +</h3> +<p>For the longest time Go had no user-level generics.</p> +<p>It did have generics, but only for the runtime!</p> +<p>This is ironic, because it proves the utility of generics while at the very same +time denying it to the user.</p> +<p>Go has relied heavily on the transpositional nature of data, using one form to represent another. +It graces you with the most important structures, which alleviates the problem:</p> +<ul> +<li>array</li> +<li>pointer</li> +<li>map</li> +<li>slice (dynamic array)</li> +<li>channel (thread-safe queue)</li> +<li>closure (anonymous function)</li> +<li>multiple-returns (pseudo tuple)</li> +</ul> +<p>In many cases you can rely on what I dub “lexical generics”, function closures that capture +lexical values implicitly capture their types as well - making closures highly type-generic +in a fascinating way. You will see this be {ab,}used in many Go codebases.</p> +<p>Often the friction of custom data structures is high enough that the desired data structure +will be transposed onto the runtime data structures.</p> +<p>Do you want a queue or stack? Use a slice. +Do you want an iterator? Use a channel. +Do you want a set or graph? Use a map. +Do you want an enum? Use an integer. +Do you want a tagged union? Use an integer kind and a fat struct.</p> +<p>As you can imagine these choices can come with significant penalties. Using a channel as +an iterator, simply because it is both type-generic and integrates with the looping syntax, adds +performance overhead due to its thread safety properties. If you don’t need threadsafety, you’re +needlessly paying for it anyway, just to coerce the language into being ergonomic to you.</p> +<p>It’s not a virtue to rely on the transpositional nature of data structures to avoid generics, +but this was the underlying argument for “why do you even need generics?”. +The true formulation is more like “we have given you enough generic structures, +just transpose onto them”.</p> +<p>Go never really told you that generics was not needed, only that it had provided enough already.</p> +<h3 id="odin"> + Odin + <a class="heading-link" href="#odin"> + <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> + <span class="sr-only">Link to heading</span> + </a> +</h3> +<p>Odin gives you parametric polymorphism: a simple form of generics that allows for the building of +type-safe, generic data structures. It is “simple” because it doesn’t come with a lot of features +or baggage. There are no traits, no method sets, and no “complex type system”.</p> +<p>Parametric: of parameters. +Polymorphism: of many shapes.</p> +<p>Put together it means “parameter that can take on many shapes”. The Odin +community shortens this to “parapoly” for brevity.</p> +<p>When people say they want generics, parapoly is usually what they want.</p> +<p>The reality: types are a compile-time-known datum. The idea that you cannot +parameterise structures and functions by a simple shape known at compile time +is silly. The problem domain: not very complex. This will rhyme when we talk about +dynamic types.</p> +<p>The punchline: Odin gives you what you actually wanted, parametric polymorphism. +It doesn’t expect you to transpose yourself into oblivion.</p> +<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, +</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? +</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"> +</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"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> +</span></span></span></code></pre></div><h2 id="no-true-dynamic-type"> + No True Dynamic Type + <a class="heading-link" href="#no-true-dynamic-type"> + <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> + <span class="sr-only">Link to heading</span> + </a> +</h2> +<blockquote> +<p>Noob: How do I do dynamic typing in Go?</p> +<p>Go: Here, use this: <code>interface{}</code> - it’s called the “empty interface”.</p> +<p>Noob: …</p> +<p>Noob: Uh, what?</p> +<p>Go: I wasn’t really meant for dynamic typing, use that or structure your program differently.</p> +<p>Noob: Ok fine, I’ll use the “empty interface” then…</p></blockquote> +<p>Dynamic programming is important and useful, it’s also not difficult to support first-class.</p> +<p>Dynamic types reduce to a fat pointer: a structure that contains two pointers, +one pointing to the data and one pointing to the type information. This allows +the program to handle arbitrary values at runtime by writing logic against +dynamic types.</p> +<p>However Go is an OOP language. It encodes the very essence of OOP: behavioural polymorpshim +based on v-tables. The term used in Go for this concept is the <code>interface</code>.</p> +<p>Like a true dynamic type, the interface is indeed a fat pointer:</p> +<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> { +</span></span><span style="display:flex;"><span> Inter <span style="color:#ff7b72;font-weight:bold">*</span>InterfaceType +</span></span><span style="display:flex;"><span> Type <span style="color:#ff7b72;font-weight:bold">*</span>Type +</span></span><span style="display:flex;"><span> <span style="color:#8b949e;font-style:italic">// --snip--</span> +</span></span><span style="display:flex;"><span>} +</span></span></code></pre></div><p>The revealing part is the separate definition for the empty interface:</p> +<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> { +</span></span><span style="display:flex;"><span> Type <span style="color:#ff7b72;font-weight:bold">*</span>Type +</span></span><span style="display:flex;"><span> Data unsafe.Pointer +</span></span><span style="display:flex;"><span>} +</span></span></code></pre></div><p>Why is this bothersome? Instead of just giving you an “any” type, +Go forces you to talk in terms of “interfaces that have no methods”.</p> +<p>Linguistically and conceptually this makes no sense.</p> +<p>This is philosphically impure.</p> +<p>Look at these beauties:</p> +<ul> +<li><code>[]interface{}</code></li> +<li><code>map[interface{}]interface{}</code></li> +<li><code>func(string, ...interface{})</code></li> +<li><code>struct { value interface{} }</code></li> +</ul> +<p>A better approach is to do what Odin does: just give you the <code>any</code> type. +Defined as simple as the concept is, a fat pointer.</p> +<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. +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// This type is named `any` at the user-level. +</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"> +</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"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> +</span></span></span></code></pre></div><p>Once you understand fat pointers, dynamic programming becomes easy.</p> +<p>Now, if you want an interface in Odin, you simply define a struct that contains +a pointer to the data and a pointer to the implementation procedure (rather than +a typeid).</p> +<p>Consider the common allocator interface:</p> +<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"> +</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"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> +</span></span></span></code></pre></div><p>It’s the same underlying idea (with a v-table of 1 to keep it ergonomic).</p> +<p>Any specialised allocator just needs to map itself onto this generic Allocator +structure and voilà, you have achieved runtime behavioural polymorphism!</p> +<p>Go has rectified the language-side of this in later releases, including the +<code>any</code> alias (equivalent to <code>interface{}</code> in all ways), but you can see how +Go’s design doesn’t reason up from first principles, but rather down from empiricism.</p> +<blockquote> +<p>We think objects are good idea.</p> +<p>We want to do them at runtime.</p> +<p>Aha, the interface type. It’s a fat pointer to a vtable and some data.</p> +<p>Look, if you want to do dynamic programming you can just use an empty interface!</p></blockquote> +<h2 id="declaration-and-assignment-syntax"> + Declaration and Assignment Syntax + <a class="heading-link" href="#declaration-and-assignment-syntax"> + <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> + <span class="sr-only">Link to heading</span> + </a> +</h2> +<p>Go and Odin both use this Pascal inspired declaration-assignment syntax <code>:=</code>.</p> +<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> +</span></span><span style="display:flex;"><span> +</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> +</span></span><span style="display:flex;"><span><span style="color:#ff7b72">var</span> variable = <span style="color:#a5d6ff">"variable"</span> +</span></span><span style="display:flex;"><span> +</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> +</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> constant = <span style="color:#a5d6ff">"constant"</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>x <span style="color:#ff7b72;font-weight:bold">:=</span> <span style="color:#a5d6ff">"foobar"</span> +</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 +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> +</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"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> +</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"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> +</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"> +</span></span></span></code></pre></div><p>What’s the problem? Well, the thing is that Go defines <code>:=</code> as a keyword. +You cannot actually place a type between <code>:</code> and <code>=</code>.</p> +<p>Once again Go fails to give you the complete idea, the grammar: <code><symbol> : <type> = <expression></code>. +Where the type can be elided to result in <code><symbol> := <expression></code>. +Where constants are the same, but with a second <code>:</code> instead of <code>=</code>.</p> +<p>Go has chosen an inconsistent approach. When the underlying grammar is elegant, +Go decides to take the shortcut and ignore the point. Odin just gives you the +elegant, consistent grammar.</p> +<p>Consider type and proc definitions:</p> +<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> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#ff7b72">type</span> Node <span style="color:#ff7b72">struct</span> { +</span></span><span style="display:flex;"><span> <span style="color:#8b949e;font-style:italic">// --snip--</span> +</span></span><span style="display:flex;"><span>} +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#ff7b72">func</span> <span style="color:#d2a8ff;font-weight:bold">Visit</span>(n Node) { +</span></span><span style="display:flex;"><span> <span style="color:#8b949e;font-style:italic">// --snip</span> +</span></span><span style="display:flex;"><span>} +</span></span></code></pre></div><p>In the Go syntax we have introduced more keywords to declare types and +functions. Why do we need extra syntax here? After all, struct and function +definitions are just regular constants!</p> +<p>In Odin, this fact is evident.</p> +<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 +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> +</span></span></span></code></pre></div><p>The syntax is consistent:</p> +<ul> +<li>consistent with other constants</li> +<li>consistently read left-to-right, with symbol first, type second, and finally the binding third</li> +</ul> +<p>After all, a struct defintion is a compile-time known value. +Thus, the <code>node</code> type is just regular constant set to a typeid.</p> +<p>Don’t believe me? Check this out:</p> +<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 +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> +</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> +<p>And if you want them to be variables instead:</p> +<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 +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> +</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"> +</span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// --snip-- +</span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span>}<span style="color:#6e7681"> +</span></span></span></code></pre></div><p>Odin takes the underlying idea of elegant, minimal and consistent grammar and +actually just hands it to you. Type definitions are <em>just</em> constants!</p> +<p>Go decides to keep the shorthand <code>:=</code> but never actually fully embraces the +underlying idea. You can’t put a type between <code>:</code> and <code>=</code>, and you are expected +to use bespoke keywords for type and function declarations.</p> +<p>Feel the inconsistency.</p> +<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> +</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> +</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> c = <span style="color:#a5d6ff">42</span> +</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> +</span></span><span style="display:flex;"><span><span style="color:#ff7b72">var</span> v = <span style="color:#a5d6ff">42</span> +</span></span><span style="display:flex;"><span>v <span style="color:#ff7b72;font-weight:bold">:=</span> <span style="color:#a5d6ff">42</span> +</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 +</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"> +</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"> +</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></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"> +</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"> +</span></span></span></code></pre></div><h2 id="conclusion"> + Conclusion + <a class="heading-link" href="#conclusion"> + <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> + <span class="sr-only">Link to heading</span> + </a> +</h2> +<p>Go develops features empirically, adopting what works practically. Odin constructs from first principles, focusing on conceptual elegance.</p> +<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> +<p>Conversely, Odin feels purposeful and coherent, designed from foundational ideas rather than incremental adaptations.</p> +<p>Despite these criticisms, Go remains practical and solid, which explains its continued popularity—and why many developers both love and hate it.</p> + + </div> + + + <footer> + + + + + + + + + + + </footer> + </article> + + + </section> + + </div> + + <footer class="footer"> + <section class="container"> + © + + 2025 + Jack Mordaunt + · + + 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>. + + </section> +</footer> + + </main> + + + + + + <script src="/js/coder.min.6ae284be93d2d19dad1f02b0039508d9aab3180a12a06dcc71b0b0ef7825a317.js" integrity="sha256-auKEvpPS0Z2tHwKwA5UI2aqzGAoSoG3McbCw73gloxc="></script> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +</body> +</html> diff --git a/public/sitemap.xml b/public/sitemap.xml @@ -3,24 +3,39 @@ xmlns:xhtml="http://www.w3.org/1999/xhtml"> <url> <loc>http://jackmordaunt.com/authors/</loc> - <lastmod>2025-07-17T11:21:04-03:00</lastmod> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> </url><url> <loc>http://jackmordaunt.com/categories/</loc> - <lastmod>2025-07-17T11:21:04-03:00</lastmod> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> </url><url> <loc>http://jackmordaunt.com/categories/development/</loc> - <lastmod>2025-07-17T11:21:04-03:00</lastmod> - </url><url> - <loc>http://jackmordaunt.com/tags/gio/</loc> - <lastmod>2025-07-17T11:21:04-03:00</lastmod> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> </url><url> <loc>http://jackmordaunt.com/tags/go/</loc> - <lastmod>2025-07-17T11:21:04-03:00</lastmod> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> </url><url> <loc>http://jackmordaunt.com/</loc> - <lastmod>2025-07-17T11:21:04-03:00</lastmod> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> </url><url> <loc>http://jackmordaunt.com/authors/jack-mordaunt/</loc> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> + </url><url> + <loc>http://jackmordaunt.com/tags/odin/</loc> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> + </url><url> + <loc>http://jackmordaunt.com/categories/opinion/</loc> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> + </url><url> + <loc>http://jackmordaunt.com/posts/</loc> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> + </url><url> + <loc>http://jackmordaunt.com/tags/</loc> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> + </url><url> + <loc>http://jackmordaunt.com/posts/why-people-hate-go/</loc> + <lastmod>2025-07-23T14:16:55-03:00</lastmod> + </url><url> + <loc>http://jackmordaunt.com/tags/gio/</loc> <lastmod>2025-07-17T11:21:04-03:00</lastmod> </url><url> <loc>http://jackmordaunt.com/tags/native/</loc> @@ -35,9 +50,6 @@ <loc>http://jackmordaunt.com/projects/</loc> <lastmod>2025-07-17T11:21:04-03:00</lastmod> </url><url> - <loc>http://jackmordaunt.com/tags/</loc> - <lastmod>2025-07-17T11:21:04-03:00</lastmod> - </url><url> <loc>http://jackmordaunt.com/tags/hugo/</loc> <lastmod>2025-07-16T14:57:56-03:00</lastmod> </url><url> @@ -47,9 +59,6 @@ <loc>http://jackmordaunt.com/tags/nostr/</loc> <lastmod>2025-07-16T14:57:56-03:00</lastmod> </url><url> - <loc>http://jackmordaunt.com/posts/</loc> - <lastmod>2025-07-16T14:57:56-03:00</lastmod> - </url><url> <loc>http://jackmordaunt.com/tags/css/</loc> <lastmod>2025-07-16T12:08:03-03:00</lastmod> </url><url> diff --git a/public/tags/go/index.html b/public/tags/go/index.html @@ -156,6 +156,11 @@ <ul> <li> + <span class="date">July 23, 2025</span> + <a class="title" href="/posts/why-people-hate-go/">Why People Love to Hate Go</a> + </li> + + <li> <span class="date">July 17, 2025</span> <a class="title" href="/projects/plato-desktop-client/">Plato Desktop Client</a> </li> diff --git a/public/tags/go/index.xml b/public/tags/go/index.xml @@ -6,9 +6,16 @@ <description>Recent content in Go on Jack Mordaunt</description> <generator>Hugo</generator> <language>en</language> - <lastBuildDate>Thu, 17 Jul 2025 11:21:04 -0300</lastBuildDate> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> <atom:link href="http://jackmordaunt.com/tags/go/index.xml" rel="self" type="application/rss+xml" /> <item> + <title>Why People Love to Hate Go</title> + <link>http://jackmordaunt.com/posts/why-people-hate-go/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/posts/why-people-hate-go/</guid> + <description><blockquote>
<p>Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition.</p></blockquote>
<p>In this opinion article I will higlight why I think people love to hate Go.</p>
<p>I&rsquo;ll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the
syntax is similar in essence (both heavily inspired by Pascal and C).</p>
<p>Unlike Go, Odin actually gives you the good ideas in their completeness -
without a complex type system or giving up any control, and without needing to
fight the ideas for a decade only to finally concede.</p></description> + </item> + <item> <title>Plato Desktop Client</title> <link>http://jackmordaunt.com/projects/plato-desktop-client/</link> <pubDate>Thu, 17 Jul 2025 11:21:04 -0300</pubDate> diff --git a/public/tags/index.html b/public/tags/index.html @@ -184,7 +184,7 @@ <li> <span class="taxonomy-element"> <a href="http://jackmordaunt.com/tags/go/">Go</a> - <sup>3</sup> + <sup>4</sup> </span> </li> @@ -227,6 +227,17 @@ <li> <span class="taxonomy-element"> + <a href="http://jackmordaunt.com/tags/odin/">Odin</a> + <sup>1</sup> + </span> + </li> + + + + + + <li> + <span class="taxonomy-element"> <a href="http://jackmordaunt.com/tags/portfolio/">Portfolio</a> <sup>3</sup> </span> diff --git a/public/tags/index.xml b/public/tags/index.xml @@ -6,20 +6,27 @@ <description>Recent content in Tags on Jack Mordaunt</description> <generator>Hugo</generator> <language>en</language> - <lastBuildDate>Thu, 17 Jul 2025 11:21:04 -0300</lastBuildDate> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> <atom:link href="http://jackmordaunt.com/tags/index.xml" rel="self" type="application/rss+xml" /> <item> - <title>Gio</title> - <link>http://jackmordaunt.com/tags/gio/</link> - <pubDate>Thu, 17 Jul 2025 11:21:04 -0300</pubDate> - <guid>http://jackmordaunt.com/tags/gio/</guid> + <title>Go</title> + <link>http://jackmordaunt.com/tags/go/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/tags/go/</guid> <description></description> </item> <item> - <title>Go</title> - <link>http://jackmordaunt.com/tags/go/</link> + <title>Odin</title> + <link>http://jackmordaunt.com/tags/odin/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/tags/odin/</guid> + <description></description> + </item> + <item> + <title>Gio</title> + <link>http://jackmordaunt.com/tags/gio/</link> <pubDate>Thu, 17 Jul 2025 11:21:04 -0300</pubDate> - <guid>http://jackmordaunt.com/tags/go/</guid> + <guid>http://jackmordaunt.com/tags/gio/</guid> <description></description> </item> <item> diff --git a/public/tags/odin/index.html b/public/tags/odin/index.html @@ -0,0 +1,237 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <title>Tag: Odin · Jack Mordaunt</title> + <meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<meta name="color-scheme" content="light dark"> + + + + +<meta name="author" content="Jack Mordaunt"> +<meta name="description" content="Coffee developer, software brewer."> +<meta name="keywords" content="blog,developer,personal,software,robust,performance,sovereign"> + + + + <meta name="twitter:card" content="summary"> + <meta name="twitter:title" content="Odin"> + <meta name="twitter:description" content="Coffee developer, software brewer."> + +<meta property="og:url" content="http://jackmordaunt.com/tags/odin/"> + <meta property="og:site_name" content="Jack Mordaunt"> + <meta property="og:title" content="Odin"> + <meta property="og:description" content="Coffee developer, software brewer."> + <meta property="og:locale" content="en"> + <meta property="og:type" content="website"> + + + + +<link rel="canonical" href="http://jackmordaunt.com/tags/odin/"> + + +<link rel="preload" href="/fonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin> +<link rel="preload" href="/fonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin> +<link rel="preload" href="/fonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin> + + + + + <link rel="stylesheet" href="/css/coder.min.6445a802b9389c9660e1b07b724dcf5718b1065ed2d71b4eeaf981cc7cc5fc46.css" integrity="sha256-ZEWoArk4nJZg4bB7ck3PVxixBl7S1xtO6vmBzHzF/EY=" crossorigin="anonymous" media="screen" /> + + + + + + + + + + <link rel="stylesheet" href="/css/coder-dark.min.a00e6364bacbc8266ad1cc81230774a1397198f8cfb7bcba29b7d6fcb54ce57f.css" integrity="sha256-oA5jZLrLyCZq0cyBIwd0oTlxmPjPt7y6KbfW/LVM5X8=" crossorigin="anonymous" media="screen" /> + + + + + + + + <link rel="stylesheet" href="/css/custom.min.931a9d02d6f7655cd0cd50317fac1204e00c54ffd0232085acc957b2db5e1283.css" integrity="sha256-kxqdAtb3ZVzQzVAxf6wSBOAMVP/QIyCFrMlXstteEoM=" crossorigin="anonymous" media="screen" /> + + + + + + +<link rel="icon" type="image/svg+xml" href="/images/self-tiny-white.svg" sizes="any"> +<link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="32x32"> +<link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="16x16"> + +<link rel="apple-touch-icon" href="/images/apple-touch-icon.png"> +<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png"> + +<link rel="manifest" href="/site.webmanifest"> +<link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5"> + + +<link rel="alternate" type="application/rss+xml" href="/tags/odin/index.xml" title="Jack Mordaunt" /> + + + + + + + +</head> + + + + + + +<body class="preload-transitions colorscheme-auto"> + +<div class="float-container"> + <a id="dark-mode-toggle" class="colorscheme-toggle"> + <i class="fa-solid fa-adjust fa-fw" aria-hidden="true"></i> + </a> +</div> + + + <main class="wrapper"> + <nav class="navigation"> + <section class="container"> + + <a class="navigation-title" href="http://jackmordaunt.com/"> + Jack Mordaunt + </a> + + + <input type="checkbox" id="menu-toggle" /> + <label class="menu-button float-right" for="menu-toggle"> + <i class="fa-solid fa-bars fa-fw" aria-hidden="true"></i> + </label> + <ul class="navigation-list"> + + + <li class="navigation-item"> + <a class="navigation-link " href="/posts/">Blog</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/about/">About</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/projects/">Projects</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/contact/">Contact</a> + </li> + + <li class="navigation-item"> + <a class="navigation-link " href="/pay-with-bitcoin/">Pay</a> + </li> + + + + </ul> + + </section> +</nav> + + + <div class="content"> + + <section class="container list"> + <header> + <h1 class="title"> + <a class="title-link" href="http://jackmordaunt.com/tags/odin/">Tag: Odin</a> + </h1> + </header> + + <ul> + + <li> + <span class="date">July 23, 2025</span> + <a class="title" href="/posts/why-people-hate-go/">Why People Love to Hate Go</a> + </li> + + </ul> + + + + + + + +</section> + + + </div> + + <footer class="footer"> + <section class="container"> + © + + 2025 + Jack Mordaunt + · + + 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>. + + </section> +</footer> + + </main> + + + + + + <script src="/js/coder.min.6ae284be93d2d19dad1f02b0039508d9aab3180a12a06dcc71b0b0ef7825a317.js" integrity="sha256-auKEvpPS0Z2tHwKwA5UI2aqzGAoSoG3McbCw73gloxc="></script> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +</body> +</html> diff --git a/public/tags/odin/index.xml b/public/tags/odin/index.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> + <channel> + <title>Odin on Jack Mordaunt</title> + <link>http://jackmordaunt.com/tags/odin/</link> + <description>Recent content in Odin on Jack Mordaunt</description> + <generator>Hugo</generator> + <language>en</language> + <lastBuildDate>Wed, 23 Jul 2025 14:16:55 -0300</lastBuildDate> + <atom:link href="http://jackmordaunt.com/tags/odin/index.xml" rel="self" type="application/rss+xml" /> + <item> + <title>Why People Love to Hate Go</title> + <link>http://jackmordaunt.com/posts/why-people-hate-go/</link> + <pubDate>Wed, 23 Jul 2025 14:16:55 -0300</pubDate> + <guid>http://jackmordaunt.com/posts/why-people-hate-go/</guid> + <description><blockquote>
<p>Go is very idiosyncratic, approximating good ideas and relying heavily on data transposition.</p></blockquote>
<p>In this opinion article I will higlight why I think people love to hate Go.</p>
<p>I&rsquo;ll do so by contrasting Go to Odin. Odin serves as an excellent comparison because the
syntax is similar in essence (both heavily inspired by Pascal and C).</p>
<p>Unlike Go, Odin actually gives you the good ideas in their completeness -
without a complex type system or giving up any control, and without needing to
fight the ideas for a decade only to finally concede.</p></description> + </item> + </channel> +</rss> diff --git a/public/tags/odin/page/1/index.html b/public/tags/odin/page/1/index.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <title>http://jackmordaunt.com/tags/odin/</title> + <link rel="canonical" href="http://jackmordaunt.com/tags/odin/"> + <meta name="robots" content="noindex"> + <meta charset="utf-8"> + <meta http-equiv="refresh" content="0; url=http://jackmordaunt.com/tags/odin/"> + </head> +</html>