Odin release highlights #

  • Replace //+ syntax with #+ (Used in cases like #+build windows)

For the rest of the many compiler changes, read the monthly release notes.


Projects shared this month #

Project Name Description
atlas-builder Atlas Builder
SpyPlayer SpyPlayer MP3 Player
gl-win32 OpenGL & win32 window creation
odin-html HTML parser
lama-odin LLama Odin bindings
sokol-gp-odin Sokol GP odin bindings
odin-rure Odin bindings for rust regex C API
odin-yyjson Odin bindings for yyjson C library
win32-software-rendering Win32 Software Rendering in odin
simd-verlet SIMD verlet integration

Streams / Youtube Content #

GingerBill #

Bill has been streaming something he wanted to work on for a long time: a WASM framework reminiscent of love2d but for the web.

Programming Rainbow #

Programming Rainbow started a cool programming series on learning SDL2 in odin.

Karl Zylinski #

Just as every other month Karl Zylinski can’t stop releasing quality odin videos.

He has also been updating his odin hot reload game template, check it out if you haven’t yet. https://github.com/karl-zylinski/odin-raylib-hot-reload-game-template

Jakub #

jakubtomsu has released another wonderful devblog on his game. I’m pretty excited to see where it goes.

Spiro Floropoulos #

Spiro Floropoulos is working on something I haven’t seen yet. It compiles odin to wasm and uses laravel (php) to do UI webdev!


Interview with Crews #

An interview with Crews, formerly known as Fast F#.

Q: What can you say about how you discovered Odin, and what appealed to you about it?

A: First off, it’s an honor to be interviewed for the newsletter and thank you for inviting me! Scheduling and Planning Optimization have been my obsession since I can remember. There’s actually a joke in my family that I’ve been doing it since before I was born. My mom was working on her PhD when she was pregnant with me and was taking classes on Operations Research, the science of planning and scheduling, so I’ve been exposed to this area of work since before I was born. For context, I don’t see myself as a developer. Professionaly, I started life as a Chemical Engineer and then moved to Industrial Engineering when I saw that the main problems faced by companies are planning and scheduling. Learning to write code was just a by product of wanting to solve these problems. This means I am language agnostic. I really don’t care what language people use.

I think you need to have a problem domain in mind when comparing languages. You can’t just say, “Language X is bad,” without first defining the context in which you want to use it. Almost every language has its place. SQL is a great language for querying sets of data, but a terrible language for writing a simulation engine. Trust me, I’ve tried 🤣. People love to engage in holy wars over which language is best but they often leave out the context of the problem they are trying to solve. Every language is terrible in some domain but may have a domain in which it is great.

My problem domain is writing high-performance simulations. Specifically, we have been working on a new Discrete-Rate Simulation Engine. When I started the project I was working in F#. I knew F# and I knew I could write high-performance F#. I even have a YouTube channel dedicated to it. Over time the limitations of the .NET Runtime began to become a limiting factor for increasing performance. As good as the Garbage Collector is in .NET, there’s nothing faster than clearing an Arena Allocator. Unions in .NET are a disaster when it comes to performance.

This lead me to search for a language that would help us unlock more performance. I initially thought of Rust since Tech Twitter wouldn’t shut up about it. I bought a couple of books and read through them but the language seems enormously complex. I had worked with C++ previously and swore I would never touch it again. I could always go all the way back to C but that felt daunting. I know C has its fans but the syntax around pointers is confusing for me.

Odin seemed purpose designed for my use case. It has manual memory management but provides easy facilities to manage allocators. The language is minimal and you can learn it in a few days. The core libraries take longer but the documentation is good and the Discord incredibly responsive. I also work with Rickard Andersson which is essentially a cheat code 😂. I have appreciate his patience with my unending questions. I think I’m bothering him less now. The language has everything I need, and nothing that I don’t.

===

Q: You’ve used Odin in a commercial application, where it replaces F#. What can you tell us about the application, how Odin came to be involved?

A: The application is a tool for modeling manufacturing systems and supply chains using Discrete-Rate Simulation which is a technique between Discrete Event Simulation and Continuous Simulation (i.e. Fluid Dynamics or any domain where rates are constantly changing).

Odin became involved due to our need for performance. I know that the .NET crowd will get all up in arms when you point out .NET isn’t as fast as writing in a low-level language. Trust me, I’ve been flamed before and told that I know nothing about performance. I knew that I had made it when a comment on HackerNews said I was clueless. It’s true, for the kinds of problems that .NET is typically used for, the performance is adequate. You can actually write some really performant code with .NET, if you know what you’re doing. You aren’t going to be writing things in the idiomatic way though. I’ve consulted for a few companies at this point to improve the performance of F#. Each time, 10x improvement was trivial because you just had to fix some obvious things, obvious if you know how to do it. And that’s really one of the problems, .NET impels you to write inefficient code. It drags you toward slow design. Can you fight the current? Yes, but you will expend much more energy doing it. In theory, you could achieve the same level of performance in .NET as you can in a low-level language, but the effort is far, far greater than just writing the low-level code.

Performance has always been a critical feature and so it was natural that we would eventually move to a language more suited for writing high-performance code. Odin is also incredibly easy to work with so productivity is actually higher because we are no longer fighting the .NET runtime to achieve the performance that we want.

===

Q: How did your colleagues react to the proposal to change the implementation language?

A: I am in a fortunate position where my leadership is highly technical. Both of the people that I report to have extensive experience writing code and building simulation models so they have an appreciation for technical topics. Andy, our president, cut his teeth on Pascal and has written plenty of low-level code himself. Amber has done extensive modeling work which involves having to write custom code for complex models. I pointed them to some videos where Ginger Bill gave an overview of the language for them to get acquainted with Odin.

On top of that, I had benchmarks I could show which illustrated the kind of performance improvements we could potentially realize. Performance is one of our defining features so any amount of distance we can put between ourselves and the competition is of interest. The fact that Odin is an incredibly well designed language helps. It smooths the learning curve.

I actually took a few days to implement the hottest part of our code and did a side by side comparison with Odin. We saw a 5x improvement in performance for that piece of code when we did a direct translation. Later on, after we ported more of the engine, we were able to take advantage of Odin’s design to see further improvement.

===

Q: We recently changed the core:math/rand API, and this impacted your software. What did this mean from your perspective?

A: Oof, that one hurt 🤣. Well, Odin isn’t 1.0 yet, so changing the API is within bounds. We actually haven’t migrated to the newest version of Odin yet, and this was one of the reasons. I’m sure we will eventually though. This change was brutal and I’m really glad I brought it up on the Discord because once Ginger Bill understood the impact it would have on us, he changed the API to be compatible. Understanding why this was a problem gets nuanced, so buckle up. Feel free to skip if pseudo random numbers bore you, but this stuff also has implications for game developent so it may be of interest.

The first thing you have to understand is that Random Number Generators (RNGs) have an internal state. When you sample a random number, the internal state of the RNG changes. This means, the random number that you get will depend on how many times you’ve sampled from the RNG.

In our world, random numbers need to be tightly controlled. We have simulations, which are “random”, but the randomness is determinisitic. We need to be able to reproduce the exact same set of random numbers every time so we can reproduce simulation results. The more challenging requirement is that the entities in our simulation need to reproduce the same random behavior, even if they are embedded in a different simulation. This means that each entity needs to have its own source of random numbers so that the sequence of numbers that are generated are the same across simulations.

For example, let’s say I have a Chicken named Clucky and it moves randomly in one of the cardinal directions: North, South, East, or West. It does this randomly on some set interval called the Move Step. Now, we want Clucky to reproduce the same random walk even if we are simulating it on a different farm (let’s ignore collisions and other nuances for now). Let’s use a single RNG, like what the new API in Odin would push you toward. The single RNG will deterministically generate the same set of moves if we give it the same seed. Let’s say the random moves we generate are the following series:

Sample Numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, …

Sample Values: N, N, W, E, S, S, E, E, N, …

The Sample Values will be Clucky’s path since it is the only entity drawing values from the RNG. We are good simulation engineers and we know to set the seed for our RNG so it produces this same set of moves every time. Now, let’s introduce a new chicken, Eggy. Clucky and Eggy now both need to generate a random walk. At each move step they’ll each sample a random direction from the RNG. Clucky samples before Eggy. Clucky will now get the odd numbered samples and Eggy will get the even. Here are Clucky and Eggy’s paths now:

Clucky Path: N, W, S, E, N …

Eggy Path: N, E, S, E, …

You can see by adding a second chicken to our simulation, we have now changed the path that Clucky will take. This is unacceptable in our domain. It makes statistical comparison of simulations far more difficult and requires you to simulate for longer and have more iterations to have the necessary statistical power when comparing results. Our simulations can have dozens if not hundreds of such entities.

The change to the core:rng API made the RNG a part of the context and using it was implicit in the calls to sample random numbers. This would have been a massive headache for us to manage since we would need to be carefully controlling the context any time we wanted to sample from a distribution. Thankfully, the discussion on Discord around this was productive. The calls to sample distributions now take an optional parameter which is the RNG. If none is specified, then the RNG on the Context is used. I think for >90% of people this is more than adequate and actually preferable. I appreciate that the team developing the Odin libraries was quick to respond and understand our use case and accomodate it.

I’m not sure of a great way of avoiding something like this in the future though. Odin is still young, it’s not 1.0 so API changes are to be expected. I knew what I was signing up for. It’s not like .NET where there’s a brutal change review process. I don’t think there’s anything to change at the moment. Once Odin hits 1.0, that changes things. API change proposals should probably go out in a newsletter of some kind or some kind of notification occurs so that people who care can subscribe and chime in.

===

Q: What’s your favorite thing about Odin, and what do you think could use some love? This could be the language semantics, the packages that come with it, the community, anything.

A: Favorite thing? Unions + Distinct types. I’ve worked with other implementations of algebraic type systems and I believe that Odin nailed Unions in a way no one else has, at least that I’ve come across. Note, the inclusion of Distinct Types is critical for the success of Unions in my opinion. Odin makes it easy to have many distinct primitives using the distinct keyword. When you combine that with the fact that Unions are just a list of different types, you get the most ergonomic syntax I’ve come across for working with Unions.

At the same time, unpacking unions is my least favorite part of Odin. Let me explain with an example. Let’s say I have the following types:

Chicken_Id :: distinct int
Turkey_Id :: distinct int
Goose_Id :: distinct int

Bird_Id :: union {
    Chicken_Id,
    Turkey_Id,
    Goose_Id,
}

Now, let’s say I have a Bird_Id and I want to switch on the value and use it. The way to do it in Odin is thus:

switch id in Bird_Id {
case Chicken_Id:
    chicken_handler(id)
case Turkey_Id:
    turkey_handler(id)
case Goose_Id:
    goose_handler(id)
}

Now, each of those *_handler procs takes the value id and the type of id depends on the switch case. Makes sense, but I come from F# and I would rather the name of id be specific to the case I’m unpacking. Something like this:

switch Bird_Id {
case Chicken_Id(chicken_id):
    chicken_handler(chicken_id)
case Turkey_Id(turkey_id):
    turkey_handler(turkey_id)
case Goose_Id(goose_id):
    goose_handler(goose_id)
}

This is akin to how F# would do it. In each of the cases I can name the contained value according to the case of the switch statement. At the end of the day, I trust Ginger Bill. Any time I’ve had a gripe with Odin and asked, “Why is it this way?” the answer made sense. I’m guessing there is some reason he did it this way but if I could change one thing about Odin, this would be it.

This is truly minor though. This barely registers on the annoyance scale compared to the insanity I have suffered with in R, C++, or .NET.

Tooling for Odin is limited compared to .NET, but that’s like saying the sky is up. It’s improving but people are doing this for free so I’m not one to judge. My dream is that JetBrains actually provides support but we’re likely a long ways off till tool vendors take up interest.

I would also love it if there was an Odin conference someday, even if it was online. I know the community is very small but I’d love to have a day where people could come together and show off what they are doing in Odin and lessons they have learned along the way. It would also be great for Ginger Bill to give a keynote on where Odin is and where he sees it going. I know that Bill has said that he language is “done” but I’m always curious about what the development team is thinking in terms of a 1.0 release and plans for the evolution of the libraries.

===

Q: Any closing remarks about your software and/or Odin?

A: Odin has been a real joy and I believe I am actually more productive now than I was in F#. I am no longer fighting .NET to achieve the performance that I want. I love that Odin is “done” and I don’t have to worry about new features being added and having to constantly learn new idioms or best practices. When you have a stable foundation, it is easier to build something larger and more complex because you don’t have the ground constantly shifting under you. My hope is that Odin will remain simple.