summaryrefslogtreecommitdiffhomepage
path: root/zig.html.markdown
diff options
context:
space:
mode:
Diffstat (limited to 'zig.html.markdown')
-rw-r--r--zig.html.markdown135
1 files changed, 68 insertions, 67 deletions
diff --git a/zig.html.markdown b/zig.html.markdown
index f8c866e5..65fd1e6b 100644
--- a/zig.html.markdown
+++ b/zig.html.markdown
@@ -5,24 +5,19 @@ contributors:
- ["Philippe Pittoli", "https://karchnu.fr/"]
---
-
[Zig][ziglang] aims to be a replacement for the C programming language.
**WARNING**: this document expects you to understand a few basic concepts in computer science, such as pointers, stack and heap memory, etc.
**WARNING**: Zig isn't considered as ready for production. Bugs are expected.
-DO NOT TRY ZIG AS YOUR FIRST PROGRAMMING EXPERIENCE.
-The compiler, even the language and its libraries aren't ready, yet.
-You've been warned.
Prior knowledge of C is recommended.
-
## Quick overview: Zig compared to C
- Syntax is mostly the same, with some improvements (less ambiguity).
- Zig introduces namespaces.
-- Try and catch mechanism, which is both convenient, efficient and optional.
+- `try` and `catch` mechanism, which is both convenient, efficient and optional.
- Most of the C undefined behaviors (UBs) are fixed.
- Compared to C, raw pointers are safer to use and less likely to be needed.
* The type system distinguishes between a pointer to a single value, or multiple values, etc.
@@ -38,8 +33,7 @@ Prior knowledge of C is recommended.
## Zig language
-
-```
+```zig
//! Top-level documentation.
/// Documentation comment.
@@ -47,9 +41,9 @@ Prior knowledge of C is recommended.
// Simple comment.
```
-
### Hello world.
-```
+
+```zig
// Import standard library, reachable through the "std" constant.
const std = @import("std");
@@ -67,7 +61,8 @@ pub fn main() void {
```
### Booleans, integers and float.
-```
+
+```zig
// Booleans.
// Keywords are preferred to operators for boolean operations.
print("{}\n{}\n{}\n", .{
@@ -109,7 +104,8 @@ i <<| 8 == 255 // u8: won't go higher than 255
```
### Arrays.
-```
+
+```zig
// An array is a well-defined structure with a length attribute (len).
// 5-byte array with undefined content (stack garbage).
@@ -156,8 +152,8 @@ try some_integers[i]; // Runtime error 'index out of bounds'.
```
### Multidimensional arrays.
-```
+```zig
const mat4x4 = [4][4]f32{
[_]f32{ 1.0, 0.0, 0.0, 0.0 },
[_]f32{ 0.0, 1.0, 0.0, 1.0 },
@@ -177,8 +173,8 @@ for (mat4x4) |row, row_index| {
```
### Strings.
-```
+```zig
// Simple string constant.
const greetings = "hello";
// ... which is equivalent to:
@@ -195,8 +191,8 @@ print("string: {s}\n", .{greetings});
```
### Slices.
-```
+```zig
// A slice is a pointer and a size, an array without compile-time known size.
// Slices have runtime out-of-band verifications.
@@ -206,8 +202,8 @@ const slice = array[0..array.len]; // "slice" represents the whole array.
```
### Pointers.
-```
+```zig
// Pointer on a value can be created with "&".
const x: i32 = 1;
const pointer: *i32 = &x; // "pointer" is a pointer on the i32 var "x".
@@ -223,7 +219,8 @@ const foo = pointer.?; // Get the pointed value, otherwise crash.
```
### Optional values (?<type>).
-```
+
+```zig
// An optional is a value than can be of any type or null.
// Example: "optional_value" can either be "null" or an unsigned 32-bit integer.
@@ -239,7 +236,8 @@ if (x) |value| {
```
### Errors.
-```
+
+```zig
// Zig provides an unified way to express errors.
// Errors are defined in error enumerations, example:
@@ -299,7 +297,7 @@ var value = try some_function();
### Control flow.
-```
+```zig
// Conditional branching.
if (condition) {
@@ -384,8 +382,8 @@ const result = for (items) |value| {
```
### Labels.
-```
+```zig
// Labels are a way to name an instruction, a location in the code.
// Labels can be used to "continue" or "break" in a nested loop.
outer: for ([_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }) |_| {
@@ -434,8 +432,8 @@ const result = for (items) |value| { // First: loop.
```
### Switch.
-```
+```zig
// As a switch in C, but slightly more advanced.
// Syntax:
// switch (value) {
@@ -454,15 +452,15 @@ var x = switch(value) {
// A slightly more advanced switch, accepting a range of values:
const foo: i32 = 0;
const bar = switch (foo) {
- 0 => "zero",
- 1...std.math.maxInt(i32) => "positive",
- else => "negative",
+ 0 => "zero",
+ 1...std.math.maxInt(i32) => "positive",
+ else => "negative",
};
```
### Structures.
-```
+```zig
// Structure containing a single value.
const Full = struct {
number: u16,
@@ -564,7 +562,8 @@ print("p.y: {}\n", .{p.y}); // 30
```
### Tuples.
-```
+
+```zig
// A tuple is a list of elements, possibly of different types.
const foo = .{ "hello", true, 42 };
@@ -572,33 +571,33 @@ const foo = .{ "hello", true, 42 };
```
### Enumerations.
-```
+```zig
const Type = enum { ok, not_ok };
const CardinalDirections = enum { North, South, East, West };
const direction: CardinalDirections = .North;
const x = switch (direction) {
- // shorthand for CardinalDirections.North
- .North => true,
- else => false
+ // shorthand for CardinalDirections.North
+ .North => true,
+ else => false
};
// Switch statements need exhaustiveness.
// WARNING: won't compile. East and West are missing.
const x = switch (direction) {
- .North => true,
- .South => true,
+ .North => true,
+ .South => true,
};
// Switch statements need exhaustiveness.
// Won't compile: East and West are missing.
const x = switch (direction) {
- .North => true,
- .South => true,
- .East, // Its value is the same as the following pattern: false.
- .West => false,
+ .North => true,
+ .South => true,
+ .East, // Its value is the same as the following pattern: false.
+ .West => false,
};
@@ -606,12 +605,12 @@ const x = switch (direction) {
```
### Unions.
-```
+```zig
const Bar = union {
- boolean: bool,
- int: i16,
- float: f32,
+ boolean: bool,
+ int: i16,
+ float: f32,
};
// Both syntaxes are equivalent.
@@ -622,8 +621,8 @@ const foo: Bar = .{ .int = 42 };
```
### Tagged unions.
-```
+```zig
// Unions can be declared with an enum tag type, allowing them to be used in
// switch expressions.
@@ -653,8 +652,8 @@ switch (nay) {
```
### Defer and errdefer.
-```
+```zig
// Make sure that an action (single instruction or block of code) is executed
// before the end of the scope (function, block of code).
// Even on error, that action will be executed.
@@ -695,24 +694,25 @@ Thus, the standard library lets developers handle memory as they need, through s
**NOTE**: the choice of the allocator isn't in the scope of this document.
A whole book could be written about it.
However, here are some examples, to get an idea of what you can expect:
-- page_allocator.
+- `page_allocator`.
Allocate a whole page of memory each time we ask for some memory.
Very simple, very dumb, very wasteful.
-- GeneralPurposeAllocator.
+- `GeneralPurposeAllocator`.
Get some memory first and manage some buckets of memory in order to
reduce the number of allocations.
A bit complex. Can be combined with other allocators.
Can detect leaks and provide useful information to find them.
-- FixedBufferAllocator.
+- `FixedBufferAllocator`.
Use a fixed buffer to get its memory, don't ask memory to the kernel.
Very simple, limited and wasteful (can't deallocate), but very fast.
-- ArenaAllocator.
+- `ArenaAllocator`.
Allow to free all allocated memory at once.
To use in combinations with another allocator.
Very simple way of avoiding leaks.
A first example.
-```
+
+```zig
// "!void" means the function doesn't return any value except for errors.
// In this case we try to allocate memory, and this may fail.
fn foo() !void {
@@ -735,8 +735,8 @@ fn foo() !void {
```
### Memory allocation combined with error management and defer.
-```
+```zig
fn some_memory_allocation_example() !void {
// Memory allocation may fail, so we "try" to allocate the memory and
// in case there is an error, the current function returns it.
@@ -759,8 +759,8 @@ fn some_memory_allocation_example() !void {
```
### Memory allocators: a taste of the standard library.
-```
+```zig
// Allocators: 4 main functions to know
// single_value = create (type)
// destroy (single_value)
@@ -846,8 +846,8 @@ fn gpa_arena_allocator_fn() !void {
```
### Comptime.
-```
+```zig
// Comptime is a way to avoid the pre-processor.
// The idea is simple: run code at compilation.
@@ -883,7 +883,8 @@ list.items[0] = 10;
```
### Conditional compilation.
-```
+
+```zig
const available_os = enum { OpenBSD, Linux };
const myos = available_os.OpenBSD;
@@ -905,7 +906,8 @@ const myprint = switch(myos) {
```
### Testing our functions.
-```
+
+```zig
const std = @import("std");
const expect = std.testing.expect;
@@ -936,45 +938,44 @@ There are more than a hundred built-ins, allowing very low-level stuff:
- etc.
Example: enums aren't integers, they have to be converted with a built-in.
-```
+
+```zig
const Value = enum { zero, stuff, blah };
if (@enumToInt(Value.zero) == 0) { ... }
if (@enumToInt(Value.stuff) == 1) { ... }
if (@enumToInt(Value.blah) == 2) { ... }
```
-
### A few "not yourself in the foot" measures in the Zig language.
-- Namespaces: names conflicts are easily avoided.
- In practice, that means an unified API between different structures (data types).
+- Namespaces: name conflicts are easily avoided.
+ In practice, that means a unified API between different structures (data types).
- Enumerations aren't integers. Comparing an enumeration to an integer requires a conversion.
- Explicit casts, coercion exists but is limited.
Types are slightly more enforced than in C, just a taste:
Pointers aren't integers, explicit conversion is necessary.
- You won't lose precision by accident, implicit coercions are only authorized in case no precision can be lost.
- Unions cannot be reinterpreted (in an union with an integer and a float, one cannot take a value for another by accident).
+ You won't lose precision by accident, implicit coercions are only authorized in cases where no precision can be lost.
+ Unions cannot be reinterpreted (in a union with an integer and a float, one cannot take a value for another by accident).
Etc.
- Removing most of the C undefined behaviors (UBs), and when the compiler encounters one, it stops.
- Slice and Array structures are preferred to pointers.
Types enforced by the compiler are less prone to errors than pointer manipulations.
- Numerical overflows produce an error, unless explicitly accepted using wrapping operators.
-- Try and catch mechanism.
+- `try` and `catch` mechanism.
It's both handy, trivially implemented (simple error enumeration), and it takes almost no space nor computation time.
-- Unused variables are considered as errors by the compiler.
-- Many pointer types exist in order to represent what is pointed.
+- Unused variables are considered to be errors by the compiler.
+- Many pointer types exist in order to represent what is pointed to.
Example: is this a single value or an array, is the length known, etc.
-- Structures need a value for their attributes, and it still is possible to give an undefined value (stack garbage), but at least it is explicitly undefined.
+- Structures need a value for their attributes, and it is still possible to give an undefined value (stack garbage), but at least it is explicitly undefined.
## Further Reading
-For a start, some concepts are presented on the [Zig learn website][ziglearn].
-
-The [official website][zigdoc] provides a reference documentation to the language.
+For a start, some concepts are presented on [zig.guide][zigguide].
-For now, documentation for standard library is WIP.
+The [official website][zigdoc] provides the reference documentation of the language. The standard library [has its own documentation][zigstd].
[ziglang]: https://ziglang.org
-[ziglearn]: https://ziglearn.org/
+[zigguide]: https://zig.guide/
[zigdoc]: https://ziglang.org/documentation/
+[zigstd]: https://ziglang.org/documentation/master/std/