Understanding the Odin Programming Language

by Karl Zylinski

This is a sample, it contains the first three chapters. Buy the full book at odinbook.com.

Contents

Contents
1: Introduction 1.1: Why learn Odin? 1.2: Language overview 1.3: Why write a book? 1.4: How to read the book 1.5: Installing the Odin compiler 1.6: If you get stuck 1.7: Acknowledgements 1.8: Copyright notice 1.9: Let's go! 2: Hellope! A tiny program 2.1: Compile and run the code 2.2: Line-by-line 2.3: What does the period in odin run . mean? 2.4: Compile without running 2.5: No need for semicolons 2.6: Where is the code inside core:fmt? 2.7: Compile a single Odin source file 2.8: There's much more! 3: Variables and constants 3.1: Declaring variables and assigning values 3.2: Another variable type and casting 3.2.1: Something strange? 3.3: Constants 3.4: Type inference defaults 3.4.1: Constants of explicit type 3.4.2: Benefits of Untyped Types 3.5: Basic types summary 3.6: Untyped Types summary 3.7: Video END OF SAMPLE4: Some additional basics 5: Making new types 6: Pointers 7: Procedures and scopes 8: Fixed-memory containers 9: Introduction to manual memory management 10: More container types 11: Strings 12: Implicit context 13: Making manual memory management easier 14: Parametric polymorphism: Writing generic code 15: Bit-related types 16: Error handling 17: Package system and code organization 18: You don't need a build system 19: Reflection and Run-Time Type Information (RTTI) 20: Data-oriented design 21: Making C library bindings (Foreign Function Interface) 22: Debuggers 23: Odin features you should avoid 24: A tour of the core collection 25: Libraries for creating video games 26: Things I did not cover 27: Where to find more Odin resources 28: Thanks for reading! 29: Appendix A: Handle-based array 30: Appendix B: Using only fixed arrays 31: Appendix C: gui_dropdown from CAT & ONION 32: Appendix D: Box2D and raylib 33: About the author
Chapter 1

Introduction

Hello! If you've been trying to learn the Odin Programming Language, but you feel like there are basic concepts that you don't fully understand, then this book is for you. Also, if you have never programmed in Odin before, but have some basic programming experience, then this book should be a good starting point as well.

By "basic programming experience", I assume you understand variables, procedures (functions), if-statements, basic arrays and loops. Don't worry though, I'll go over how to do those things in Odin.

I also assume that you know how to run programs from a command-prompt or terminal.

Why learn Odin?1.1

I wouldn't say there is one big reason for learning Odin, but rather a big number of small reasons. Odin doesn't try to fundamentally solve any new problems. There are many "big agenda" languages out there, meaning languages that try to introduce completely new ways of thinking about programming. Odin is not one of them. The reasons for learning Odin may vary depending on your background. Here are two examples of such backgrounds:

If you come from a higher level language such as C#, JavaScript or Python, but want to learn a low level language, where performance and control is easily attainable, then Odin may be for you. I think it is a great first low level language. Odin's modern features and simplicity cuts out some noise you find in older low level languages. This makes the programming fun and lets you focus on the low level concepts, without getting overwhelmed. I usually say that Odin is "low level with high level feeling".

A low level language is "closer to the hardware" than a high level language. There are less layers of abstract things between your code and the computer. In a low level language you have more control, but less things are done automatically for you.

If you've used the C Programming Language, but don't find it as fun to program in as it could be, then Odin may be for you. I have worked on big video game engines written in C. I would say that Odin point-for-point addresses many of the issues I've had with C, while also incorporating some of my favorite C best practices, straight into the language.

For example, Odin makes heavy use of zero-is-initialized, which is a great way to program C. It also comes with built-in support for allocators.

If you don't know C or C++ then don't be intimidated by the "From C / C++" bubble just before this paragraph. I try to keep most information that assumes you know C or C++ within those bubbles. They are safe to skip.

As a final answer to "Why learn Odin?", I'll give a short anecdote: In 2023-2024 I used Odin to create my own video game: CAT & ONION. Never before have I been able to finish and ship a whole game, all by myself. In the past I always felt some degree of friction from whichever programming language I used. That friction usually built up over time, until I dropped the project. With Odin enough friction was removed, making it possible for me to ship something.

Language overview1.2

Let's talk a bit about what Odin is, so that you have some reasonable expectations before reading more.

Odin is a compiled language. You have to run the source code through the Odin compiler to produce an executable that you can later run without having to involve the Odin compiler.

Odin is a simple language. Great care has been put into the design of the language so that the different parts work together as a simple whole.

Odin uses manual memory management. You manually decide the lifetime of allocated memory. This means that you are in control of when memory is deallocated. It is not done automatically for you. This gives benefits in regards to performance and memory usage. It may seem scary to programmers that come from languages that employ automatic memory management. But fear not, Odin comes with built-in ways to track memory leaks and practical ways to handle temporary memory allocations. In chapters 9 to 13 we will look at different aspects of manual memory management.

Odin is not object-oriented. Your code will mainly use procedures (functions), if-statements, loops and structs to get things done. This makes the code very simple. The object-oriented programmer will find new ways to write reusable and generic code, that in general has better performance characteristics than object-oriented code.

Odin is well suited for data-oriented programming. This means that it is easy to write Odin code that utilizes the CPU in an efficient manner. We will discuss data-oriented programming in chapter 20.

Finally, the language really gets out of the way and lets you do things your way. This is one of many reasons why "joy of programming" is marketed as an important feature of the language.

Why write a book?1.3

I wanted to write a book about Odin for two reasons. Firstly: Odin's online documentation is missing some things and not always very pedagogical. By transforming several years of Odin programming experience into a book, I aim to bridge that gap.

Secondly: I've been active within the Odin community for several years. During that time I've seen some questions and confusions over and over again. Sometimes these questions can only be properly answered if you take a step back and look at the big picture of why something in the language works the way it does.

With that in mind I decided to write this book. I want to provide holistic explanations of things people often find confusing, and in doing so provide a deep understanding.

How to read the book1.4

Each chapter deals with a certain part of the language. I don't fully cover every aspect of the language. Instead, each chapter tries to explain the basics of a certain language feature, and then follow that up with more advanced topics. Some of these advanced topics are actually not hard to understand, it's just that some things may not be apparent until you've used the language for a long time. I hope that I can save you some of that time.

You'll see bubbles like this one every now and then. In these you'll find extra clarifications as well as some trivia that is interesting, but not vital.

This book is not meant to be a "tutorial" where you follow step-by-step instructions to reach a specific outcome. Instead, I've tried to make this book enlightening: On top of explaining how to write Odin code, I also provide explanations of why things work the way they do. Sometimes I'll talk about how things work "under the hood". I strongly believe that understanding your tools will make you a better craftsperson.

I've written this book in an informal style, hoping that it can be enjoyed in its entirety. That said, if you already know Odin fairly well, then I think you can skip directly to chapter 6.

Installing the Odin compiler1.5

I will not go over how to install the Odin compiler. For that I refer to the official Getting Started guide on the Odin website.

After installing the compiler I assume that you have the folder where you installed it your path. Meaning that you can run odin from a command prompt or terminal anywhere on your computer.

Should you have any trouble installing the compiler, then I also have a video on the topic, targeted at Windows users:

https://www.youtube.com/watch?v=yq5VabsGz_4

Note that I install Odin from source in this video. This is not a requirement, you can use the pre-built releases that the Getting Started page mentions.

If you get stuck1.6

If you can't figure out how to do something specific in Odin, and you can't find any help in this book, then I recommend checking these resources, in the order stated:

  1. Check the official language overview. It is not exhaustive, but searching around in there will answer many questions.
  2. Look inside demo.odin. It is an example that comes with the compiler. It showcases many different features of the language. You'll find a local copy in <odin>/examples.
  3. Search in the core and base library collections. Pull the <odin>/core and <odin>/base folders into your text editor and just search around in there. Those library collections are well written and easy to read. It is a great way to learn many Odin concepts.
  4. Ask in the #beginners channel on the Odin Discord server. It is a chat server that has thousands of members. Many questions get answered very quickly.

When I write <odin> in a path I refer to the location where you installed the Odin compiler.

Finally, you're warmly welcome to join my own Discord server (not the same as the official Odin Discord server mentioned above). It's a friendly place where you can ask questions about Odin and also discuss game development, or tell me about that typo you found in this book!

There's also a channel for posting cat pictures!

Acknowledgements1.7

Thanks to all my supporters on patreon.com for their donations! It truly helped a lot.

Thanks to Tobias Möllstam for proof-reading.

Thanks to PythagoRascal for proof-reading.

Thanks to Bill Hall (gingerBill) for proof-reading, and for creating the Odin Programming Language!

Thanks to Geraldine Lee for proof-reading and being a stellar partner while I've been stuck with my nose in the computer.

Copyright notice1.8

Please don't redistribute this book without my explicit permission. If you somehow got hold of this book without paying for it, then please consider buying a copy at odinbook.com.

Let's go!1.9

That's it for the introduction, enjoy the book!

/Karl Zylinski (December, 2024)

Chapter 2

Hellope! A tiny program

In this chapter we'll look at just about the smallest possible Odin program. It's a program that just shows the message "Hellope!" in a console. First I'll show the code and explain how to compile and run it. Then I'll talk about what each line of code does. Finally, I'll go over some points that I think are good insights related to this tiny program.

By console I mean a command prompt (Windows) or a terminal (macOS / Linux).

"Compilation" is the process by which code gets translated into an executable that your computer can run.

Compile and run the code2.1

Here's the code of our tiny program:

package hellope

import "core:fmt"

main :: proc() {
	fmt.println("Hellope!")
} 

Open your favorite text editor and copy the code above into a file. Save the file as hellope.odin inside an empty folder.

Popular text editors for writing Odin code are Sublime Text, VS Code and Vim.

Use a command prompt or terminal to navigate to the folder where you saved hellope.odin. Once inside it, type:

odin run .

Please include the period, with a space before it! This will compile your program into an executable, and then run it. The program should print "Hellope!".

Shows how I navigate to c:\code\hellope and running 'odin run .'. The program is compiled and run, and outputs 'Hellope!'.
Shows how I use the command prompt cmd on Windows to navigate to the folder where I saved hellope.odin. I compile and run the program using odin run .

If you use macOS or Linux, then you need to use forward slashes in the path:

cd /path/to/your/code

Note that this is a console application. The message will be printed to the command-prompt or terminal. No graphical window will be opened.

Print is a funny word. It's an old hand-over from early programming languages and literally refers to a printer. These days print goes to a "standard output stream", which often means some kind of text console.

Line-by-line2.2

Let's go through the program line-by-line, starting with this one:

main :: proc() {

This declares a new proc called main. Proc is short for procedure. Some languages refer to procedures as functions. The main procedure is where the program starts. The program runs from the main procedure's opening curly brace { to the closing curly brace }. I will talk more about procedures in chapter 7.

Strictly speaking, functions are side-effect free procedures, meaning that they do not modify anything outside the procedure. Since there's no promise of being side-effect free in Odin, the term procedure is used.

The program runs from the opening brace to the closing brace

The only thing the main procedure does is print "Hellope!". It does this using the fmt package. The line

import "core:fmt"

fetches the fmt package from the core collection. The core collection comes with the Odin compiler and contains an enormous amount of useful code. The fmt package contains procedures that can print text and also format strings. The procedures inside fmt can be used by typing fmt.some_procedure_name(). In this case we use fmt.println and pass it the message to put on the screen:

fmt.println("Hellope!")

fmt is short for "format". Odin doesn't always try to keep names short, but I guess fmt is used so often that the name was made a bit more keyboard efficient.

The line at the top of the program says

package hellope

This is the package name. For now, just note that this line must be the same for all Odin files within a folder. The name must also be unique project-wide, in the sense that no other imported package uses the same name. I go over this in more detail in chapter 17.

Let's now look at some interesting details about this example program.

What does the period in odin run . mean?2.3

The . in odin run . refers to the current folder. This means that the Odin compiler will take all files ending with .odin in the current folder, and compile them as a package. By default odin run . assumes that you want to create an executable program based on this package. It will look for a procedure called main inside the package, which will be the starting location of your program. When it has created the executable, it will run it.

There are other options than creating executables. For example you could create a library. A library won't need a main procedure.

For more information, run odin build -help and look into the -build-mode flag.

If you had more than one Odin source file in the current folder, then all of them would be compiled as part of your program.

Compile without running2.4

If you replace run with build, meaning that you execute the following:

odin build .

Then the program will just be compiled into an executable, without running it. In both the build and run cases, you'll be able to find the resulting executable next to your Odin source files. The name of the executable will be the name of the folder.

Shows the hellope.exe next to hellope.odin
Regardless of if you execute odin run . or odin build . you'll always get an executable that you can run later without involving the Odin compiler.

If you are on Windows but can't see the .exe or .odin file endings within the file explorer, then please go into the View tab and check File name extensions. Computers are pretty much unusable without enabling this.

No need for semicolons2.5

There's no need to put a semicolon (;) at the end of each line, as is required in many other languages.

Semicolons are optional, but I would encourage to simply not use them. The absence of semicolons fits well with the aesthetics of Odin. However, you can use them if you really want to!

Also, if you really want to make sure that you don't accidentally use them by old habit, then there is a compiler flag to make any unnecessary semicolon into an error: -vet-semicolon

Compiler flags are added when you run the compiler:

odin run . -vet-semicolon

In fact, I recommend you compile with the flag -vet. That one includes a whole bunch of other helpful checks, such as making it an error if you have unused imports.

You can see a list of all the different variations of -vet if you run

odin run -help

Where is the code inside core:fmt?2.6

Packages are just folders with Odin files inside them. The folder with your hellope.odin file is one package. And from your hellope package you also import the core:fmt package, which is also just a folder. But where is that fmt folder?

It's part of the core collection. The core collection comes as source code along with the Odin compiler. This means that you can look at what the code inside it does. I encourage you to do this, as you can learn a lot from reading that code. You'll find the core:fmt package in <odin>/core/fmt. The println procedure you used can be found in fmt_os.odin within that folder.

Since core comes as source code, I recommend pulling it into your text editor so you can easily jump to the definition of things in there. I also recommend pulling in the base folder that exists next to core.

The contents of the fmt package: 5 odin files, where one is fmt_os.odin, which contains the println procedure.
The contents of <odin>/core/fmt. The println procedure can be found inside fmt_os.odin

Compile a single Odin source file2.7

If you want to just compile a single Odin file instead of all the files within a folder, then add the -file flag:

odin run hellope.odin -file

This treats a single file as a complete package instead of fetching all the files within a folder.

There's much more!2.8

This chapter was just a quick crash course, an appetizer. Throughout this book we'll return to many of these concepts in depth.

From here on, most chapters will focus on specific areas of the language.

Chapter 3

Variables and constants

Odin has a syntax for declaring and assigning variables that will look unfamiliar to people coming from JavaScript, C or C#. But it might look familiar to those who have programmed in Pascal or Go.

The syntax of a language defines the form of the language; how it looks.

In this chapter we'll look at how to create variables. We'll also look at how to convert variables from one type to another. As we shall see, there is something strange afoot with how plain numbers like 7 work in relation to variable types, which will bring us to talking about constants. At the end of the chapter I hope you'll see how Odin's interplay between variables and constants creates an elegant whole.

Declaring variables and assigning values3.1

Variables are, like the name suggests, possible to vary. Meaning that the code can change a variable's value.

You declare a variable like this:

number: int

This variable is named number. It is of type int, short for integer. Note the : between the name and the type. It is the symbol Odin uses for declarations.

Odin is a strongly typed language, meaning that the language is strict about types: You can only put integers into integer variables. You cannot change the type of a variable after it has been declared.

What value does number have? Since we didn't specify any, it will have the value zero. This is true for all variables of all types. Technically speaking, since we didn't specify any value, then the underlying memory that holds the variable's value will be all zeroes. As we'll see in the summary at the end of this chapter, this can have a few different meanings for non-numeric types.

In C, writing just int number; will leave the variable non-initialized. It can contain any garbage memory! This is almost never what you want, and a source of many bugs. In Odin it will be initialized to zero by default. However, if you want to leave a variable non-initialized, then you can write:

number: int = ---

This is mostly useful in very specific performance-sensitive situations.

You can assign a new value to an already existing variable:

number: int
number = 7

Note that doing number = 7 with no pre-existing variable called number, will fail to compile.

If you want to both declare a variable and assign a value to it, then you can combine the : and the = on a single line, like this:

number := 7

This creates a new variable number of type int and gives it the value 7. In this case you didn't have to say what type number should have. Instead, the type is inferred from the value on the right hand side. This means that the compiler looks at the value on the right and decides what type the variable should have based on the value. In this case the type is inferred to int.

The anatomy of declaration and assignment. Remove the type int to infer the type from the value on the right. Remove = 7 to make this a declaration without an assignment. Remove : int to make this an assignment to a previously declared variable.

Here's a small program that creates a variable, prints its value, changes it and then prints it again:

package variable_example

import "core:fmt"

main :: proc() {
	number := 7
	fmt.println(number) // prints 7
	number = 12
	fmt.println(number) // prints 12
} 

Putting // in front of some text in your code file creates a comment. The comment goes from // to the end of the line. You can also write

/* comment */

to create a multi-line comment. Multi-line comments can be nested.

Note the usage of := on the line where we declare and initialize number and that we use a plain = when we later change its value.

Another variable type and casting3.2

The type int we saw earlier can only store whole numbers. If we want to store decimal numbers, then we can use the type f32:

decimal_number: f32

The f stand for "floating point number", usually called just "float". A floating point number is a method for storing decimal numbers. The 32 means that it uses 32 bits of memory (or 4 bytes) to store the decimal number. Again, since we are not specifying a value, decimal_number will be zero by default.

Using more bits for your floats increases the biggest number it can store as well as its precision. However, more bits eat more memory. So many programmers use f32 by default, even though most computers have 64 bit processors.

For example, video games use floats a lot, but very often the f32 type is precise enough.

When we previously wrote number := 7, then the compiler inferred number to be of type int. How can we declare a variable of type f32, but also initialize it to 7, using a single line of code? There are two ways:

decimal_number: f32 = 7

or

decimal_number := f32(7)

These two variants have the same end result. The first one looks like decimal_number: f32, but we've added = 7 at the end. In the second case we have skipped saying what type decimal_number is, and instead rely on the type being inferred from the right hand side: f32(7). This means that we take 7 and cast it, or convert it, to the type f32.

f32(7) almost looks like we are running a procedure called f32 and feeding it the value 7. Whenever you see a type name followed by parenthesis like this, then it is a cast.

Decimal numbers can of course use decimals:

decimal_number: f32 = 7.42

But what happens if we do the following?

decimal_number := 7.42

In this case decimal_number will be inferred to have the type f64, not f32.

So when you write decimal_number := 42.07, then there seems to be some kind of default choice of for giving it the type f64. We shall soon see where these default choices come from.

Something strange?3.2.1

Now we'll get to the stuff that may initially seem strange, but will end up being very useful once you get it. The following code compiles just fine:

number := 7
decimal_number: f32 = 7

However, the next snippet does not compile. It will complain that it cannot automatically convert int to f32:

number := 7
decimal_number: f32 = number

It will compile if you do an explicit cast:

decimal_number := f32(number).

Why is that? At a surface level, 7 seems to be of type int because typing number := 7 makes a variable of type int, where the type int is inferred from the 7 on the right hand side. But this does not make any sense because you can also assign 7 to a variable of type f32 without an error:

decimal_number: f32
decimal_number = 7

decimal_number: f32 = 7 also works.

As I've said Odin is strongly typed, so if 7 was of type int then assigning it to an f32 would be a compilation error.

The answer is that a plain 7 is not of type int. It is a constant, and constants have a slightly different system for types than variables do. To understand this fully, let's take a step back and talk about what constants are.

Constants3.3

Constants are things that only exist at compile time. Since they only exist at compile time, they cannot be changed while the program is running.

By compile time I refer to things that happen as the Odin compiler is running. Anything that happens later, as the program is running, is referred to as run time.

I already said that a plain number like 7 is a constant. But you can also create a named constant like this:

CONSTANT_NUMBER :: 12

Note that we use :: to create named constants. You can assign a constant to a variable like this:

CONSTANT_NUMBER :: 12
number := CONSTANT_NUMBER

I use SCREAMING_SNAKE_CASE when naming constants. That's just the naming convention used by the core collection, which I have adopted.

Note that we declare and assign to number using :=. Just like before, the type of number will be inferred to int. The two lines above are actually identical to just typing

number := 12

You can think of named constants having their value "copy-pasted" into wherever you use their name. You can also think of a stand-alone 12 as a nameless constant.

Now, I said that constants have a slightly different type system compared to variables. One could say that constants have a slightly weaker type system. The type of CONSTANT_NUMBER :: 12 is Untyped Integer. An Untyped Integer can be implicitly converted to any integer or floating point type, as long as that type can 'accommodate' the value.

This is why decimal_number: f32 = 7 is allowed. 7 is a constant of type Untyped Integer, and that type allows for an implicit conversion (or cast) to the type f32.

I write Untyped Integer capitalized like this to make it easier to read. I know, the idea of an Untyped Type is quite strange. But as you'll find out by programming more Odin, this system is very comfortable without feeling vague.

What's up with the "as long as that variable can 'accommodate' the value" part above? Here's something that will not compile:

BIG_CONSTANT_NUMBER :: 100000000
small_number: i8 = BIG_CONSTANT_NUMBER

small_number is of type i8 (8 bit signed integer), the biggest value it can contain (accommodate) is 127. BIG_CONSTANT_NUMBER is a constant of type Untyped Integer. When the compiler tries to shove BIG_CONSTANT_NUMBER into small_number, then it sees that the value of this constant is bigger than 127, so it refuses to do so.

"8 bit integer" means that the computer has eight binary numbers (bits) at its disposal to represent an integer. The biggest number one can represent with 8 bits is 255. But since signed integers can be negative, then only half of that range can be used. The range of the 8 bit signed integer is therefore -128 to 127.

There are more Untyped Types than just Untyped Integer. Constants containing a decimal point such as DECIMAL_CONSTANT :: 27.12 are of type Untyped Float. An Untyped Float can only be assigned to a floating point variable such as f16, f32 or f64 (with one exception, which we'll see below). The code below will not compile, because we are trying to assign an Untyped Float to an integer variable. The integer variable cannot accommodate decimal numbers.

DECIMAL_CONSTANT :: 27.12
my_integer: int = DECIMAL_CONSTANT

There's an exception to this. If you have an Untyped Float with all zero decimals, then it can be implicitly converted to an integer:

DECIMAL_CONSTANT :: 7.0
my_integer: int = DECIMAL_CONSTANT

Equivalent to

my_int: int = 7.0

The integer must still be able to accommodate the value. This will not compile:

my_int: i8 = 400.0

Again, an i8 cannot store anything bigger than 127.

We say that Untyped Floats are allowed to be implicitly converted to integers as long as they don't get truncated, meaning that no decimals get cut off.

At the end of this chapter I'll present a list of all the Untyped Types in Odin.

Type inference defaults3.4

As I mentioned before, when we type something like

decimal_number := 13.38

then this variable will be of type f64. This default choice is specified by the Untyped Type system that constants use:

These type inference defaults should not be confused with the implicit conversions that Untyped Types also allow:

decimal_number: f32
decimal_number = 7.42

This is allowed because 7.42 is an Untyped Float, which may be implicitly cast to any float type, such as f64, f32 or f16. It has nothing to do with type inference defaults.

Constants of explicit type3.4.1

You can give a constant a specific type, if you really want to. Note how we wedge a type between the two : below.

DECIMAL_CONSTANT: f32 : 7.42

When using this constant, no implicit type conversions will happen. You'll need to cast the constant to be able to use it as a f16 or f64.

Explicitly typed constants aren't used that much. I have never used them in my own code.

There is a similarity between this syntax and the := syntax used with variables. Compare the line above to the one below:

decimal_variable: f32 = 7.42

In both cases the type comes after the first :. Then you put a : or a = after the type depending on if you want a constant or a variable.

Benefits of Untyped Types3.4.2

The system of Untyped Types means that both these assignments are valid:

decimal_32: f32
decimal_32 = 0.5

decimal_64: f64
decimal_64 = 0.5

This may not seem like a big deal, but if you have programmed in C or C#, then you may have been annoyed with having to type 0.5f every time you want to assign 0.5 to a 32 bit floating point number.

That is because those languages have distinct types associated with literals like 0.5 and 0.5f. In C 0.5 is a 64 bit floating point number and 0.5f is a 32 bit floating point number. Odin delays that choice of distinct type, leaving 0.5 untyped for as long as possible, until it really needs to choose a type for it.

A literal refers to values written directly in the source code, such as 0.5 and "cat".

Basic types summary3.5

We've seen the types f32, f64 and int. We refer to these as basic types, because they are built right into the language itself. There are more basic types in Odin. Here are some of them:

Signed integers

Unsigned integers

Floating point numbers

Boolean types

By "zero value" I refer to what you get when you type my_variable: bool. The memory for this variable will be all zeroes, but what those zeroes are interpreted as varies from type to type. For a bool it means false. For a string it means "" (empty string).

Strings

In contrast to C, a string knows how long it is and does not use null-termination. Therefore len(some_string) can tell you the length of the string without having to scan through it in search for a null character. The cstring types uses a null-terminator.

Runes

You'll find some additional basic types in the official overview.

Untyped Types summary3.6

Untyped Types are the types used by constants. Since constants only exist at compile time, so do Untyped Types.

There are six kinds of Untyped Types. Each has its own rules for what kind of implicit conversions it allows. Also, each Untyped Type has a default type to pick when type inference occurs.

Untyped Booleans

Untyped Integers

Untyped Floats

Untyped Strings

Untyped Runes

Something that will not compile is x: i8 = '猫' because '猫' uses more than 8 bits to store its numerical value. The i8 cannot accommodate this Untyped Rune.

Using i16 would make it compile.

Untyped nil

Video3.7

I've made a video where I explain how the Untyped Types system works:

https://www.youtube.com/watch?v=qLYga3iCmt0

End of sample

Thanks for reading! This is the end of the sample. If you want to buy the rest of the book, then please go to odinbook.com.

The full book contains these chapters:

  1. Introduction
  2. Hellope! A tiny program
  3. Variables and constants
  4. Some additional basics
  5. Making new types
  6. Pointers
  7. Procedures and scopes
  8. Fixed-memory containers
  9. Introduction to manual memory management
  10. More container types
  11. Strings
  12. Implicit context
  13. Making manual memory management easier
  14. Parametric polymorphism: Writing generic code
  15. Bit-related types
  16. Error handling
  17. Package system and code organization
  18. You don't need a build system
  19. Reflection and Run-Time Type Information (RTTI)
  20. Data-oriented design
  21. Making C library bindings (Foreign Function Interface)
  22. Debuggers
  23. Odin features you should avoid
  24. A tour of the core collection
  25. Libraries for creating video games
  26. Things I did not cover
  27. Where to find more Odin resources
  28. Thanks for reading!
  29. Appendix A: Handle-based array
  30. Appendix B: Using only fixed arrays
  31. Appendix C: gui_dropdown from CAT & ONION
  32. Appendix D: Box2D and raylib
  33. About the author