My one issue is (and I'm fully aware it will never happen) I do wish there was some sort of first-class solution to inheritance. I've grown to love procedural programming, but some problems really are just better solved with a more OOP approach. Just because classes exist does not mean they need to be used.
But as far as a language to "get stuff done" with as few tradeoffs as possible, Odin is about as good as I can imagine a language being.
Never bought into rust (have studied, have a (mostly AI-generated app in rust).
Wrote some Zig but Odin is even less overhead for me. I first loved Zigs built-in build system but having tried to wrap/use C libraries from both, I must say I prefer Odin. Wrapping some sqlite 3 API’s for my first little Odin program - just because I need so little of the API that it seems easier this way - and speaking to C from Odin is a pleasure.
That is, imho, where Rust fails the most - the second part is the C++’ish approach to memory management (RAII) - that’s not how systems programming or games (I’m told) tend to work.
To each their own. I had some fun with Rust too, but for me, Odin seems the most appealing :)
In your opinion, could a minimal system to develop in Odin be squeezed into a device like the one(s) you targeted?
That's assuming maybe some tweaks to the toolset, doing without some niceties, but not cutting core features out of the language.
Asking 'cause I have a passing interest in programming languages that allow for native development on really small implementations (think sub-1MB on bare metal). The list of candidates doesn't seem long.
But mainly, language doesn't have a special gimmick. The main idea (imo) is it is opinionated to have defaults to cater for majority of the cases. So once you get used to it, it is pleasure to write C-like code in it.
What does this mean? Who told you that?
I don't believe Xtensa (ESP32) is supported yet, but people have been asking for it, so it may happen at some point. ARM is well supported now though, obviously.
Here's a UI framework, if you scroll down you'll see it on a Raspi Pico: https://github.com/MadlyFX/Ansuz
They largely don't deeply elaborate, which is sad because I am a professional game developer who is interested in precisely presented knowledge so I can apply it to my work.
My interpretation is that games want to allocate large pools of resources, like GPU buffers, cpu memory, etc, and reuse that memory over and over. Ie: Reinitialize it.
In my experience, RAII is my preferred pattern for certain things (std::lock_guard), and you can almost certainly express the majority of these "uber game dev patterns" using RAII/smart pointers/etc, but the c++ implementation of these "uber game dev patterns" tends to be more complicated (and imo esthetically ugly) compared to really well written C.
These new languages (zig, odin, jai) appear to be attempts to improve C to allow an alternative to C++ that doesn't have the ugly baggage that C++ has.
My angle is systems programming, and there, it absolutely matter. If you are performance sensitive, then you try to avoid crossing the user-space -> kernel boundary more than you have to.
Eg, ask for lots of memory, manage with arenas.
Interestingly Odin and Zig both lean into this heavily. Rust went a different route but has tried later to bolt on pluggable allocators.
Could a toolset to develop in Odin be made to run on (not just target) an STM32 microcontroller like you used?
> It's just C with nicer syntax and modern data structures
That suggests the above would (in theory) be possible for any device that's roughly in the same class as "can run a C compiler". Correct?
But if a human-oriented language were to be designed to also be better for LLMs, I think it would involve deeply expressive syntax that can succinctly but distinctly represent a very broad set of common operations. Succinct so context can be managed well, distinct so completions don't confuse one thing for another, broad so as much "reasoning" can be taken away from the LLM as possible. An anti-C. A new take on the goals of Java and Go to be languages that protect the application from the Junior Developers You're Likely To Hire.
I somewhat think it would also involve application state images ala Smalltalk. LLMs seem okay at generating small deltas. Many deltas sequenced together invites compounding error. LLM generated apps are unlikely to lead to common libraries being compentized and extracted out of the application to share with other applications; it seems like LLM code generation is already a "married to a specific project" act already. So, having a living state image might reveal some benefits by leaning into incrementally developing the application in situ, as a whole.
As on some references, Ryan Fleury did an episode on Wookash podcast on RAD debugger showing ECS like approach.
IMO, their RAII critique is a but nuanced, but because of their personality the discourse often gets polarising.
Edit: the sibling comment just proved my last point.
Reference counting has deterministic timing, you can run a deconstructor without registering objects for deletion and running any known finalizers (what you need to do in all GC langs I’m aware of.)
But a lot of languages aren't like that, and so this doesn't translate. Obviously in Rust with Vec<Goose> that's only 8 allocations, each local Goose lives in the stack - or, if you knew up front there were 500 geese, you Vec::with_capacity(500) and it's a single allocation - but similar is true in many languages, Java is an outlier.
Building a database, operating system, etc. absolutely requires fine tuned control over allocation. You can get around some of these things in Rust, but it will fight you. You'll effectively have to turn your back on the containers in std and build your own vectors, maybe even your own Box, etc.
Odin looks really appealing to me at one level, but I'd have a hard time switching to any language at this point that doesn't have a borrow checker story.
Ah... The school of what I like to call "maximum opinions and minimal evidence". Aggressive arrogant dismissal of anything except their exact view (and for Muratori, you're also "woke" for good measure), coupled with a complete lack of _hard evidence_ to back up their views. In that regard, they're not unlike "investment advice" instagram influencers.
This gives the misleading impression that ordinary memory allocators are materially different from arena allocators. They aren't. Both types of allocators first ask for a big block of memory from the kernel, then dole that memory out in userspace. There's no need to cross the userspace/kernel boundary more often than you need to, especially when you consider that you can replace the standard platform allocator with whatever you want.
To wit, C doesn't emphasize arena allocation anywhere near as much as Zig et al do, and yet nobody alleges that C is somehow less suitable for systems programming than these languages. Have you considered why that is? Because, for the most part, arena allocation doesn't make a significant difference, and in the places where it actually does make a difference, you can trivially build an arena allocator on top of the standard allocator.
My interpretation is that games want to allocate large pools of resources, like GPU buffers, cpu memory, etc, and reuse that memory over and over. Ie: Reinitialize it.
They might say this, but there isn't a good technical rationalization here since anyone can create a global data structure just as easily in C++.
on the other hand there are no constructors (just normal functions) so you cant initialize values in place, only stack allocate and return. i think rust needs to add in place init and change the rules from "always init at declaration site" to "must be initialized at first use" like kotlin.
the big missing piece is custom allocators that let you use something like a bump arena with the same convenience as system malloc. they already exist on nightly but nobody knows when they will land on stable.
honestly thats the biggest problem with rust, they come up with a lot of useful changes but then take ages to stabilize because the core team is overworked. they also have a kind of perfectionist culture as a reaction to all the half baked features shipping in C++.
there should be a stage between nightly and full release where feature is in stable toolchains behind a cfg flag and you get a warning if upstream crates use it. show commitment to shipping it in time but still make it clear that it can change (in minor incompatible ways) before release.
This isn't true and doesn't make any sense. Smart pointers don't need to enter into it. If you need a lot of something you make a vector and allocate once.
Also I remember they mentioned it’s not necessary to free memory if you’re about to close your program, because the OS will take the memory back.
It is an extremely niche scenario to need a program to shut down so much faster that you can't even deallocate memory. If you don't make lots of small allocations in the first place the deallocations won't take any time.
Obviously you need to gracefully deinitialise some things, like audio or other devices, but that’s beyond the discussion.
It's actually a pretty big advantage to destructors to deal with stuff like this as well as memory and locks.
IMO, their RAII critique is a but nuanced, but because of their personality the discourse often gets polarising.
I think it gets polarizing because they are both undeniably sharp programmers but don't have any real evidence of this stuff, they are just grasping at rationalizations.
You can even use the same ownership model as rust (borrowing et al.) with non copyable types.
Besides, as mentioned java's allocations are much closer to something like using an arena in a low-level language, then a "slow" malloc. It uses thread-local allocation buffers, where you have a large buffer with a pointer pointing to the start of the free region. Allocation is just a pointer bump, not even needing synchronization since it is per a single thread. As it gets full, the GC moves out still alive objects in the background and resets the buffer.
This is pretty much the most efficient one can be after per-object type arenas and simply not allocating.
Jon Blow worked on numerous AAA games that required “that level” of optimization. And he’s one of the very few developers in the last 15 years who have managed to sell more than a million copies of a game running on a scratch built 3D engine.
You can disagree with their opinions, but they certainly have the experience to back those opinions up.
Allocations are really really cheap in Java by the way, so I don't get how 500 allocations would even be an issue.
The perf argument against RAII is very abstract and is less "RAII causes bad performance" and more "the kind of design that leads you to reach for RAII is the kind of design that's bad for performance." There exist similar hand-wavy arguments against many other C++/Rust features.
More generally, "you shouldn't even want that" is basically a meme at this point in programming language design. Every new-ish language has some version of it.
Goose jim = make_a_goose_somehow(); // Java, so jim is on the Heap, no way around it
When you make that variable in Rust... let jim : Goose = make_a_goose_somehow(); // Rust, jim is on the stack
Now, if we make a bunch of geese, maybe in a loop, and we put them into our growable array type... ArrayList<Goose> geese = new ArrayList<Goose>();
// ... some loop eventually
Goose a_goose = somehow_get_this_goose(); // That's an allocation
geese.add(a_goose);
But in Rust... let geese: Vec<Goose> = Vec::new();
// ... some loop eventually
let a_goose : Goose = somehow_get_this_goose(); // But this is not
geese.push(a_goose);That said. You asked about C, which I use for my job. Most every large C code base end up abandoning the stdlib (such as it is) and inventing their own. Since they do, we aren’t as hurt by abandoning it as you would be in e.g. Rust - the rust stdlib is useful, the C stdlib is.. not great.
Once you abandon the stdlib, a likely first stop is writing your own routines for allocating and freeing memory. There are different approaches here, from glib’s or sqlite’s alloc and free routines to people writing an allocator abstraction (basically a struct with a vtable for allocating/realloc/free) and when you build your own “stdlib” around this abstraction, you are fine.
As for why you may want arenas vs other allocation strategies, that again deals with how often you are comfortable going across the user-space/kernel boundary and how clever you can be with your allocations or how much internal fragmentation you can accept.
As with all other stuff, it depends. But arenas are often great when you can assert that a series of objects share the same lifetime (death time, rather). In these cases, your amortize the syscall cost, have nearly no additional work to manage the memory (contrast to e.g. the complexity of jemalloc) and can free a series of objects in constant time.
People who are motivated by a superiority complex or by the wish to impress a herd of twitter followers hardly if ever produce a thought I want to read.

Do you want to learn the Odin Programming Language and demystify low-level programming?
Then this book is for you.
Understanding the Odin Programming Language is a book that teaches both basic and advanced Odin concepts. You'll learn about procedures, manual memory management, parametric polymorphism, data-oriented design, and much more.
The target audience is anyone with some programming experience. Odin is a simple yet powerful language, making this book a great introduction to low-level programming, regardless of your background.
A programming language is a tool. By understanding your tools, you will become a better craftsperson. Therefore, this book does not just explain how to write Odin code. It also explains why the language works the way it does.
What people say:
I highly recommend Karl Zylinski's excellently written book on Odin—perfect for anyone who wants to learn and understand the Odin programming language. -Bill "gingerBill" Hall, creator of Odin.
Karl makes a great job at explaining Odin. I had a good experience with garbage collected language like Golang and the book really helped me to transition to a non garbage collected language like Odin. -Review on store.zylinski.se by Kevin D.
I never read, I get distracted easily. But the writing style here is so good, that I didn't have any issues reading through the whole thing in a couple days. -Review on store.zylinski.se by Shaka.
Version 1.10 released! Read the release notes.
Available formats:

Beautifully laid out and easy to navigate. A portable HTML file with all the fonts and images baked in. Similar to a PDF, but nicer to use.
The optimal reading experience on a computer. Can also be read on a phone or tablet.
Available on:
store.zylinski.se HTML+eBook Itch HTML+eBook
If you are unsure of which version to get, then I recommend buying it from store.zylinski.se or Itch. On there you'll get both the HTML and eBook versions.
Version 1.10
[dynamic; N]T type (Fixed Capacity Dynamic Array) instead of the Small_Array. The Fixed Capacity Dynamic Array deprecates the Small_Array.core.Get the latest version by just re-downloading the book from wherever you bought it.
Version 1.9
core:os in order to match the changes introduced by "os2". Background: The whole core:os package was replaced during February 2026. After this replacement, some code example changes were needed. A lot of code that used core:os still works, but usages of os.read_entire_file and os.write_entire_file needed some changes.Version 1.8
This version does some major changes to the strings chapter (chapter 11). It has been heavily revised and expanded. Some changes are:
cstring16 type.odin run . -keep-executable (new Odin behavior)..(Type) syntax used to check the variant of unions.@init and @fini.bit_set initializers to a more appropriate location.Version 1.7
rand.int_max range clarificationVersion 1.6
from_1_to_2draw_image instead of sometimes using draw_texture.Version 1.5
I have read the whole book, essentially doing an extra editing pass. I've made a huge amount of changes that make the text clearer. Here are some of the bigger changes:
My_Union in 5.3#load in chapter 26@rodata in chapter 26@init and @fini)#reverse in "Chapter 4: Some additional basics"Version 1.4
Version 1.3
level not being a pointer in 13.2 and added some info about why it needs to be a pointer.Version 1.2
bit_set chapter.bit_set versus using a-set-that-is-a-map.Small_Array has has been improved for clarity.delete works.@static on local variables does.Version 1.1 Released shortly after 1.0. Fixes a bunch of typos.

Karl Zylinski is an independent game developer and programming educator. He is the author of Understanding the Odin Programming Language, a book that teaches Odin in an approachable way. Karl is the creator of the video game CAT & ONION. It was the first commercial video game made in the Odin Programming Language. He also runs a YouTube channel where he shares educational material on Odin and game development.
In the past Karl has worked as a game engine programmer at Our Machinery, Bitsquid and Autodesk. He has also worked as a game programmer at Hazelight (A Way Out) and Friendly Foe (SOULBOUND).
Karl has a bachelor's degree in astrophysics. In his free time he likes to play video games, hike, go bouldering and play piano.
Visit his website and blog at zylinski.se.
Chat about Odin and game development on his Discord server.