Skip to content

Instantly share code, notes, and snippets.

@jakubtomsu
Last active April 16, 2026 16:32
Show Gist options
  • Select an option

  • Save jakubtomsu/0e2f68c6af735b9f50659da08902f061 to your computer and use it in GitHub Desktop.

Select an option

Save jakubtomsu/0e2f68c6af735b9f50659da08902f061 to your computer and use it in GitHub Desktop.
Proposal for new odin-lang.org front page examples.
/*
The examples on the front page of odin-lang.org aren't very good.
This is my proposal for a new replacement. The following examples
should introduce most of the core language features.
They were written with C, Go and Python programmers in mind.
I've tried to make the code relatively similar to what one
would write in practice in a real project, while keeping the line
count small.
I think they should appear on the website in this order:
1. Matrix and array programming
2. Dynarrays and maps
3. Reflection
4. Iterators, unions, or_*
5. Structured Data
6. #soa and SIMD
7. context and tracking allocator
8. vendor libs - raylib hello world
*/
package new_odin_front_page_examples
//
// MARK: linalg, matrix and array programming
//
import "core:math/linalg"
import "core:fmt"
main :: proc() {
// Vectors in Odin are just fixed arrays
a := [3]f32{0, 1, 2}
b := [3]f32{0, 0, 1}
// Scale 'b' by 2 and do element-wise addition
c := a + b * 2
fmt.println(c) // [0, 1, 4]
// Vectors can be swizzled (fields reordered)
// just like in shader languages
fmt.println(c.zyx) // [4, 1, 0]
// Many operators are built-in, and the linalg
// package contains everything else you need.
fmt.println(linalg.length(c)) // 4.123...
// Matrix math is also built-in!
scale_z := matrix[3, 3]f32{
1, 0, 0,
0, 1, 0,
0, 0, 10,
}
d := scale_z * c
fmt.println(d) // [0, 1, 40]
}
//
// MARK: #soa + SIMD dot products etc
//
import "base:intrinsics"
import "core:fmt"
f32x8 :: #simd[8]f32
dot_product_simd :: proc(a, b: [3]f32x8) -> f32x8 {
ab := a * b
return ab.x + ab.y + ab.z
}
sum_vector_lengths_simd :: proc(vectors: #soa[][3]f32) -> f32 {
lane_sums: f32x8
// This loop is processing 8 values at a time!
for i := 0; i + 7 < len(vectors); i += 8 {
vec := [3]f32x8{ // Raw aligned memory loads
(cast(^f32x8)&vectors.x[i])^,
(cast(^f32x8)&vectors.y[i])^,
(cast(^f32x8)&vectors.z[i])^,
}
length_squared := dot_product_simd(vec, vec)
lane_sums += intrinsics.sqrt(length_squared)
}
return intrinsics.simd_reduce_add_pairs(lane_sums)
}
main :: proc() {
// X, Y and Z components will be in separate contiguous blocks of memory.
data := make_soa_aligned(#soa[][3]f32, 64, 32)
data[0] = {1, 0, 0}
data[1] = {2, 2, 2}
// fill data...
length_sum := sum_vector_lengths_simd(data)
fmt.println(length_sum)
}
//
// MARK: Structured Data
// Enumerated arrays, using, bit_sets
//
import "core:encoding/json"
import "core:fmt"
Entity_Handle :: u32
Entity_Base :: struct {
position: [3]f32,
velocity: [3]f32,
}
Player_Entity :: struct {
// 'using' brings the fields into the struct namespace.
using base: Entity_Base,
health: i32,
// Like an array of booleans, but each flag takes up 1 bit.
flags: bit_set[Player_Flag],
// Enumerated array, can be indexed only with 'Hand'
hand_items: [Hand]Item,
}
Player_Flag :: enum u8 { Grounded, Stunned, Hungry }
Hand :: enum { Left, Right, }
Item :: enum { None = 0, Pickaxe, Shovel, Sword, Apple, }
main :: proc() {
player := Player_Entity{
position = {1, 10, 0},
health = 10,
flags = {.Grounded},
hand_items = {
.Left = .None,
.Right = .Pickaxe,
}
}
serialized := json.marshal(player, {pretty = true}, context.temp_allocator) or_else nil
fmt.println(string(serialized))
}
//
// MARK: dynarrays and maps, dedup rand
//
import "core:math/rand"
import "core:fmt"
main :: proc() {
// Allocate memory for a few 8-bit integers
data := make([dynamic]u8, 10)
defer delete(data)
for &val in data {
val = u8(rand.int_range(0, 3))
}
// De-duplicate using a map.
// Map to a struct{} (empty structure with size of 0 bytes) is a set.
unique_data: map[u8]struct{}
delete(unique_data)
for val in data {
unique_data[val] = {}
}
fmt.printfln("Original: %v\nUnique: %v", data, unique_data)
// The result could look something like this:
// Original: [0, 0, 2, 0, 0, 1, 0, 2, 0, 0]
// Unique: map[1, 2, 0]
}
//
// MARK: Reflection - print struct fields sizes
//
import "core:reflect"
import "core:fmt"
My_Struct :: struct {
name: string,
counter: u8,
position: [3]f32,
buffer: [64]byte,
}
main :: proc() {
print_struct_field_sizes(My_Struct)
// Output:
// name: 16 bytes
// counter: 1 bytes
// 3 bytes padding
// position: 12 bytes
// buffer: 64 bytes
}
print_struct_field_sizes :: proc($T: typeid) {
offset := 0
for field in reflect.struct_fields_zipped(T) {
// If offsets don't match, there's padding.
if offset != int(field.offset) {
fmt.printfln("% 20i bytes padding", int(field.offset) - offset)
offset = int(field.offset)
}
fmt.printfln("% 12s: % 6i bytes", field.name, field.type.size)
offset += field.type.size
}
}
//
// MARK: Iterators, multiple returns and or_*, defer
//
import "core:fmt"
// App event
Event :: union {
Key_Input,
Draw,
// ...
Exit,
}
Key_Input :: struct { key: int }
Draw :: struct {}
Exit :: struct {}
main :: proc() {
events := []Event{
Key_Input{ key = 10 },
Draw{},
Key_Input{ key = 5 },
Exit{},
Draw{},
}
event_loop: for event in poll_events(&events) {
switch v in event {
case Exit:
break event_loop
case Key_Input:
fmt.println("key pressed", v.key)
case Draw:
fmt.println("Drawing...")
}
}
}
// Custom iterator procedure over an event slice.
// The iterator stops when ok=false.
poll_events :: proc(it: ^[]Event) -> (result: Event, ok: bool) {
if len(it) == 0 do return nil, false
result = it[0]
it^ = it[1:]
return result, true
}
//
// MARK: context and tracking allocator
//
import "core:mem"
import "core:fmt"
main :: proc() {
tracking_state: mem.Tracking_Allocator
mem.tracking_allocator_init(&tracking_state, context.allocator)
context.allocator = mem.tracking_allocator(&tracking_state)
// The context is passed implicitly everywhere,
// so all allocations happen with tracking allocator from now on.
// Do allocations and intentionally forget to free...
// In practice, use context.temp_allocator for short-lived data.
_ = make([]f32, 1000)
for i in 1..=5 {
_ = make([]byte, i * 10)
}
// Print all leaks
for addr, entry in tracking_state.allocation_map {
fmt.printfln("%s:%i leaked %i bytes",
entry.location.file_path, entry.location.line, entry.size)
}
// Output looks something like:
// test.odin:28 leaked 40 bytes
// test.odin:28 leaked 20 bytes
// test.odin:28 leaked 10 bytes
// test.odin:28 leaked 30 bytes
// test.odin:28 leaked 50 bytes
// test.odin:15 leaked 4000 bytes
}
//
// MARK: vendor libs - raylib hello world
//
import rl "vendor:raylib"
main :: proc() {
rl.InitWindow(800, 600, "Hello Odin + Raylib!")
defer rl.CloseWindow()
for !rl.WindowShouldClose() {
rl.BeginDrawing()
defer rl.EndDrawing()
rl.ClearBackground(rl.DARKBLUE)
rl.DrawText("Hellope!", 20, 20, 40, rl.WHITE)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment