375 lines
10 KiB
Markdown
375 lines
10 KiB
Markdown
|
## Intro
|
||
|
|
||
|
Before we start:
|
||
|
- might be running slow - streaming + old laptop
|
||
|
- no slides, just text
|
||
|
- live coding demo
|
||
|
- will try to cover most cool things
|
||
|
- but no multithreading/async/atomics and C interop details in talk
|
||
|
|
||
|
Who am I?:
|
||
|
- Ivan Notaroš - nothke
|
||
|
- indie gamedev for 10+ years
|
||
|
- studied architecture
|
||
|
- started by modding - 3D modeling
|
||
|
- Unity, C# since ~2013
|
||
|
- many game jams: https://nothke.itch.io/
|
||
|
- Unity had too many limitations, esp for procgen, progressively went lower level
|
||
|
- custom engine in C++ since 2020
|
||
|
- making a rally game: Shakedown Rally in it
|
||
|
- heard of Zig a few years ago
|
||
|
- kept hearing of cooler and cooler features
|
||
|
- started making an engine just to see how easy it would be to move C++ to Zig
|
||
|
- I stream gamedev on twitch too: https://twitch.tv/nothke
|
||
|
- Windows user all my life 😢
|
||
|
|
||
|
## Zig
|
||
|
- Hard to put in an elevator pitch
|
||
|
- Fell in love with language and community - https://ziglang.org
|
||
|
- Don't know where to start, I'll try my best
|
||
|
|
||
|
Zig (language) facts:
|
||
|
- Zig is an imperative,
|
||
|
- structured,
|
||
|
- general-purpose,
|
||
|
- statically typed,
|
||
|
- compiled,
|
||
|
- system programming language
|
||
|
|
||
|
History:
|
||
|
- designed by Andrew Kelley
|
||
|
- https://andrewkelley.me
|
||
|
- first version (0.1) since 2016
|
||
|
- currently at 0.14 dev, 0.13.0 stable
|
||
|
- since 0.10 - self-hosted
|
||
|
- since 2020, Zig software foundation: https://ziglang.org/news/announcing-zig-software-foundation/
|
||
|
|
||
|
Goals:
|
||
|
- "better C"
|
||
|
- simple, clear, readable
|
||
|
- very explicit
|
||
|
- maintainable
|
||
|
- robust
|
||
|
- sane defaults
|
||
|
- fast: runtime AND compile
|
||
|
- no hidden allocations
|
||
|
- write all in Zig
|
||
|
- minimal dependencies
|
||
|
- no UB in debug or safe
|
||
|
- unambigous, context-free syntax
|
||
|
- one obvious way to do things
|
||
|
|
||
|
Some really cool bits (apart from already mentioned):
|
||
|
- all-in-one cross-compiling toolchain
|
||
|
- include and seamlessly interoperate with C code
|
||
|
- comptime - powerful metaprogramming - written in zig
|
||
|
- integrated build system - written in zig
|
||
|
- no hidden allocations - easy to reason about memory
|
||
|
- amazing standard library
|
||
|
- which is completely comprehensible! (unlike C++ STL 😛)
|
||
|
- decentralized package manager
|
||
|
- zls
|
||
|
- pointer disambiguation
|
||
|
- no exceptions - error types
|
||
|
- no header files (!!!)
|
||
|
- bit-packing types
|
||
|
- SIMD vectors
|
||
|
- no function or operator overloads
|
||
|
- strong formatting convention
|
||
|
- OOP-lite
|
||
|
- no macros
|
||
|
- if it looks like a function, its a function. Fields are just fields!
|
||
|
|
||
|
### The toolchain
|
||
|
- all-in-one
|
||
|
- cross compile from-to any system
|
||
|
- compile C and C++
|
||
|
- include C code
|
||
|
- translate-c - C to zig
|
||
|
- -ofmt=c - zig to C
|
||
|
- very fast
|
||
|
- build system written in Zig
|
||
|
- just `zig build run`
|
||
|
- no CMake!
|
||
|
- integrated tests
|
||
|
- 4 compiler modes `--release=[mode]` :
|
||
|
- debug
|
||
|
- safe
|
||
|
- fast
|
||
|
- small
|
||
|
- lazy compiler
|
||
|
- only compiles what you use
|
||
|
|
||
|
## Live demo!
|
||
|
|
||
|
### installing
|
||
|
- with VSCode:
|
||
|
- install Zig extension
|
||
|
- ctrl+shift+P
|
||
|
- install zig
|
||
|
- install zls
|
||
|
- alternatively:
|
||
|
- with zvm https://www.zvm.app/
|
||
|
- `zvm i --zls master` or `0.13.0` (for now)
|
||
|
- install binary
|
||
|
- build zls
|
||
|
- sudo apt install zig
|
||
|
|
||
|
### Language walkthrough
|
||
|
|
||
|
const and var
|
||
|
- `: T =`
|
||
|
- initialization
|
||
|
- `const` - immutable
|
||
|
- const resolved at compile time if it can be
|
||
|
- can act as an alias to types
|
||
|
- `var` - mutable
|
||
|
|
||
|
integers
|
||
|
- unsigned: `u8`, `u16`, `u32`..
|
||
|
- signed: `i8`, `u16`, `u32`..
|
||
|
- but also arbitrary width: `i2`, `u6`, `i31`..
|
||
|
- casting - peer type resolution
|
||
|
- narrow to wide - allowed
|
||
|
- wide to narrow - disallowed, must be explicit @intCast
|
||
|
- if compile-time known - casting checked at compile time
|
||
|
- overflow is an error
|
||
|
- but explicit overflow operator `+%`, `-%`
|
||
|
- Note: `const a = 1;` is a `comptime_int`
|
||
|
|
||
|
- floats `f16`, `f32`, `f64`, `f128` and `f80`
|
||
|
|
||
|
pointers (single item):
|
||
|
- `*T`
|
||
|
- `&` - address of operator
|
||
|
- can't be null
|
||
|
- (..we'll come back to more pointers..)
|
||
|
|
||
|
`[N]T` - arrays
|
||
|
- on stack, compile-time known size
|
||
|
- size part of type
|
||
|
- `[3]T`
|
||
|
- `[_]T` - inferred size from initialization
|
||
|
- unambiguously values
|
||
|
- unlike C which pretend to be pointers
|
||
|
|
||
|
`[]T` - slices
|
||
|
- `const slice: []T = &arr;`
|
||
|
- or `const slice = arr[0..];`
|
||
|
|
||
|
strings
|
||
|
- what strings..? They're just `[]u8`
|
||
|
- "string class" not needed, `std.mem.-` functions are rich enough for every need
|
||
|
- For unicode there's `std.unicode.-`
|
||
|
|
||
|
`++` `**` - compile-time array operators
|
||
|
- `arr ++ arr2` - concatenates
|
||
|
- `arr ** 3` - repeats
|
||
|
|
||
|
structs
|
||
|
- `const MyStruct = struct {}`
|
||
|
- fields
|
||
|
- always public
|
||
|
- rearranged to better fit memory
|
||
|
- unless `extern`
|
||
|
- can be default initialized
|
||
|
- are namespaces
|
||
|
- namespaced functions
|
||
|
- if first parameter is `MyStruct`, acts as a "method"
|
||
|
- if self needs to mutate, pass as pointer `self: *MyStruct`
|
||
|
- initialization
|
||
|
- uninitialized fields not allowed
|
||
|
- (but fields can be default initialized ^)
|
||
|
- force uninitialized with `= undefined`
|
||
|
- explicitely shoot yourself in the foot! (unlike C)
|
||
|
- files are structs too!
|
||
|
- `packed`
|
||
|
- bools become 1 bits
|
||
|
- arbitrary-sized ints become bit-sized
|
||
|
- no ctors/dtors - more on that later..
|
||
|
|
||
|
enums and unions
|
||
|
- enums
|
||
|
- (bare) unions
|
||
|
- known which type
|
||
|
- no type punning
|
||
|
- tagged unions
|
||
|
- use a backing enum
|
||
|
- switch
|
||
|
- polymorphism on stack!
|
||
|
- ^ enums and unions also act as namespaces that can have functions! 😉
|
||
|
|
||
|
Zig has no operator overloads!
|
||
|
- = is always a (shallow) copy
|
||
|
- [] only works on arrays, slices and multi-item pointers
|
||
|
- & always a pointer to - looking at C++
|
||
|
|
||
|
But I'm a gamedev and really need my vector arithmetic overloads 😭
|
||
|
- Don't worry! There are built-in Vectors! 😍
|
||
|
|
||
|
`@Vector(3, i32)`
|
||
|
- SIMD out of the box
|
||
|
- can index
|
||
|
- cannot loop through
|
||
|
- but can cast into compatible array `[3]f32 = @Vector(3, f32)`
|
||
|
|
||
|
functions
|
||
|
- `fn`
|
||
|
- parameters always const
|
||
|
- compiler can infer copy or const-ref, depending on size
|
||
|
- params
|
||
|
- return must be known
|
||
|
- but comptime expressions possible
|
||
|
- function pointers
|
||
|
|
||
|
control flow
|
||
|
- `if (bool)`
|
||
|
- `while (bool)`
|
||
|
- `for (array) |x| {}`
|
||
|
- `|x|` capture bars
|
||
|
- expression creates variable
|
||
|
- range `0..`
|
||
|
- multi-item
|
||
|
- inline - unrolls loops
|
||
|
- switch
|
||
|
- exhaustive
|
||
|
|
||
|
!?
|
||
|
- `!T` errors and `?T` optionals
|
||
|
- ! error unions
|
||
|
- error enum
|
||
|
- type example: divide by zero
|
||
|
- handling errors:
|
||
|
- try
|
||
|
- catch
|
||
|
- switch
|
||
|
- ? optionals
|
||
|
- can be `null`
|
||
|
- `?*T` - nullable pointers
|
||
|
- don't consume extra space
|
||
|
- `opt.?` unwraps value, if null throws error
|
||
|
- `opt orelse 0` if null use another value
|
||
|
- `if (opt) |value| {}` if not null, unwraps
|
||
|
- `while (opt) |value| {}` runs until null
|
||
|
- can be used to implement iterators `while (iter.next()) ..`
|
||
|
|
||
|
### Disambiguation of Pointers
|
||
|
- in C/C++, a pointer can be
|
||
|
- dereferenced `*ptr`
|
||
|
- indexed `ptr[3]` - and not bounds checked
|
||
|
- added to `ptr + 1`
|
||
|
- `nullptr`
|
||
|
- not known if it points to a null terminated string..? 🤷♂️
|
||
|
|
||
|
- Zig disambiguates all these and puts them in separate types:
|
||
|
- `*T` - single-item pointer - cannot be indexed
|
||
|
- `[]T` - slice - bounded, cannot be dereferenced with t.*
|
||
|
- `[*]T` - multi-item pointer - unbounded
|
||
|
- `[:0]` - sentinel-terminated, 0 in this case
|
||
|
- `?*T` `?[]T` - nullable
|
||
|
- `*anyopaque` - equivalent to void*
|
||
|
- `*align(1:0:1) T` - pointers can also hold alignment and bit offset in their type
|
||
|
- `[*c]` - can do all - but use it only for interoperating with C code!
|
||
|
|
||
|
- Why? intent is much clearer!
|
||
|
|
||
|
### Comptime
|
||
|
- no macros, no templates, no constexpr
|
||
|
- call any function at compile time!
|
||
|
- types are types
|
||
|
- (at compile time only)
|
||
|
- can be used to return types to create generics
|
||
|
- example: Optional(T)
|
||
|
- full static reflection
|
||
|
- e.g. looping through fields
|
||
|
- https://gist.github.com/travisstaloch/71a7a2bc260997abe06016c619b40bf2
|
||
|
- `anytype`
|
||
|
- function parameter type that can ONLY be inferred at compile-time
|
||
|
- similar to template function `auto` parameters in C++
|
||
|
- `comptime var`
|
||
|
- can be mutated but only at compile-time
|
||
|
- acts as const at runtime
|
||
|
|
||
|
## Memory Management
|
||
|
|
||
|
Memory management in other languages:
|
||
|
- manual (C) - malloc() free()
|
||
|
- RAII (C++)
|
||
|
- GC (Java/C#/python/Go)
|
||
|
- compile time resolved (rust)
|
||
|
|
||
|
Zig - manual, BUT, unlike C:
|
||
|
- `defer`
|
||
|
- executes at the end of the scope
|
||
|
- like RAII - BUT controlled by the user
|
||
|
- `errdefer` like defer but only when error is thrown
|
||
|
- has allocators
|
||
|
|
||
|
### Allocators
|
||
|
- interface used in std with anything that allocates heap memory
|
||
|
- PageAllocator
|
||
|
- the "dumb" one
|
||
|
- makes syscalls
|
||
|
- FixedBufferAllocator
|
||
|
- provide a buffer, can be on stack
|
||
|
- not resizeable
|
||
|
- GeneralPurposeAllocator
|
||
|
- can catch leaks in debug
|
||
|
- ArenaAllocator
|
||
|
- can discard entire chunks
|
||
|
- TestingAllocator
|
||
|
- only available in tests
|
||
|
|
||
|
- Demo how to use with `std.ArrayList`
|
||
|
|
||
|
## Built-in Tests
|
||
|
- `test "My Test" {}`
|
||
|
- `std.testing.expect-`
|
||
|
- just `zig build test`
|
||
|
|
||
|
## Package manager
|
||
|
- build.zig.zon
|
||
|
- not centralized
|
||
|
- hash to check code correctness
|
||
|
- `zig fetch --save "link"`
|
||
|
|
||
|
## Cons
|
||
|
- not 1.0 yet
|
||
|
- changes from version to version
|
||
|
- async not there yet
|
||
|
- C/C++ ecosystem is much older and versatile
|
||
|
- no built-in vtable-inheritance (dynamic dispatch)
|
||
|
- but you can do your own in comptime
|
||
|
- example (old): https://github.com/alexnask/interface.zig
|
||
|
- no lambdas
|
||
|
- but https://github.com/ziglang/zig/issues/6965
|
||
|
|
||
|
## Community and Resources
|
||
|
- Online:
|
||
|
- discord: https://discord.gg/invite/zig
|
||
|
- ziggit: https://ziggit.dev/
|
||
|
- Dude the Builder: https://www.youtube.com/@dudethebuilder/videos
|
||
|
- Offline:
|
||
|
- Software you can love https://sycl.it/
|
||
|
- meetups on zig
|
||
|
|
||
|
## Future of Zig
|
||
|
- goal of 0.14.0: super fast compile times
|
||
|
- getting rid of LLVM:
|
||
|
- with LLVM 170MB, without 4.4
|
||
|
|
||
|
## Conclusions
|
||
|
- wHeRe dOeS zIg fIt iN tHe mOdeRn wOrLd??
|
||
|
- Aren't you convinced by the talk..?
|
||
|
- Reduces friction
|
||
|
- Companies already using Zig:
|
||
|
- Tigerbeetle https://tigerbeetle.com/
|
||
|
- Bun https://bun.sh/
|
||
|
- Uber (build system)
|
||
|
- `zig zen`
|
||
|
- What about Odin, jai..?
|
||
|
- Will do the same talk in Hamburg for code.talks
|
||
|
|
||
|
Epilogue:
|
||
|
- Thanks! Now you can code in Zig⚡ !
|
||
|
- nothke: https://nothke.github.io/
|