diff --git a/README.md b/README.md index a9a393c..ea7630f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ See [talk notes](talk.md) +[main.zig](src/main.zig) has most of the examples from the talk reconstructed. + To run `zig build run` To build C samples, run: diff --git a/c/raii.cpp b/c/raii.cpp index ce989c8..bbc02eb 100644 --- a/c/raii.cpp +++ b/c/raii.cpp @@ -8,12 +8,16 @@ public: MyClass() { - ptr = malloc(sizeof(100000000)); + std::cout << "Allocating 1MB\n"; + + // Allocate 1MB for no reason: + ptr = malloc(sizeof(1000 * 1000)); } ~MyClass() { free(ptr); + std::cout << "Destroyed 1MB\n"; } }; @@ -21,7 +25,9 @@ MyClass myClass; int main() { - std::vector vec; - vec.push_back({}); + // Trick question, how many times is it constructed and destroyed? + std::vector vecOfMyClasses; + vec.push_back(myClass); + vec.push_back(myClass); } \ No newline at end of file diff --git a/src/main-old.zig b/src/main-old.zig deleted file mode 100644 index 57d7d8a..0000000 --- a/src/main-old.zig +++ /dev/null @@ -1,43 +0,0 @@ -const std = @import("std"); - -fn calc(a: i32) i32 { - return a; -} - -const SOmethin = enum { - One, - Two, - Three, -}; - - -fn Optional(comptime T: type) type { - return struct { - valid: bool, - value: T, - }; -} - -fn add(a: anytype, b: anytype) @TypeOf(a + b) { - return a + b; -} - -const DivisionError = error{DivisionByZero}; - -fn divide(a: f32, b: f32) !f32 { - if (b == 0) - return DivisionError.DivisionByZero; - - return a / b; -} - -pub fn main() !void { - - - std.debug.print("All your {s} are belong to us.\n", .{"codebase"}); - - const vec = @Vector(4, i32){ 1, 0, 1, 0 }; - const vec2 = @Vector(4, i32){ 0, 1, 0, 1 }; - - std.debug.print("vec: {}", .{vec + vec2}); -} diff --git a/src/main.zig b/src/main.zig index a87c65e..193485d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,114 +1,353 @@ const std = @import("std"); -const Other = @import("other.zig"); -// Struct +// const/var and integers -const Vector2D = packed struct { - x: i5 = 2, - y: i23, +fn demoIntegers() void { + const signedInt: i32 = -2345; + const unsignedInt: u32 = 34; + const signedChar: i8 = 4; + const unsignedShort: u16 = 5362; + + const sum = signedInt + unsignedInt + signedChar + unsignedShort; - fn name(self: Vector2D) void { - _ = self; // autofix + var mutableInt = sum + 3; + mutableInt += sum; - } + // Casting from narrow to wide type is allowed + const arbitraryWidth: i2 = -1; + const widerType: i4 = arbitraryWidth; + _ = widerType; // autofix - fn init() void {} - fn deinit() void {} -}; + // Casting to a narrower type is resolved at compile-time here + const narrowerType: i3 = arbitraryWidth; + _ = narrowerType; // autofix -// Functions + // Casting from wide to narrow must be explicit with @intCast + var wide: i32 = 0; + wide = 345; + const narrow: u16 = @intCast(wide); + _ = narrow; // autofix -fn add(a: i32, b: i32) i32 { - return a + b; + var overflow: u8 = 0; + //overflow -= 1; // This will cause an overflow error + overflow -%= 1; // ..But if we use +% or -% this is allow overflow operator } -fn setTo3(a: *i32) void { - a.* = 3; +// Arrays + +fn demoArrays() void { + const arr = [3]u32 {23, 45, 67}; + // or: const arr = [_]u32 {23, 45, 67}; + + std.log.info("arr: {}", .{arr.len}); + + // You can initailize to zeroes like this: + var arr2 = std.mem.zeroes([16]u32); + + arr2[0] = 3; + + // 2 ways of getting slices: + const slice1: []u32 = &arr2; // Casting array pointer to slice + const slice2 = arr2[0..]; // Getting with range + + // Multi-object for loops: + for (slice1, slice2) |v1, v2| { + if (v1 != v2) + std.log.err("Impossible!", .{}); + } } -// Error unions +// Structs -const DivideError = error{ - DivivisionError, +const Vector2D = struct { + x: f32 = 0, // default initialized + y: f32 = 0, }; -fn divide(a: f32, b: f32) !f32 { - if (b == 0) { - return DivideError.DivivisionError; - } else { - return a / b; +fn demoStruct() void { + var uninitedVec: Vector2D = undefined; // Explicitly uninitialized + const initedVec: Vector2D = .{ .x = 0, .y = 0 }; // Explicitly initialized + const defaultInitedVec: Vector2D = .{ .x = 0, .y = 0 }; // Default initialized + + uninitedVec.x = undefined; // Force it to be used + + std.log.debug("uninitedVec: {}", .{uninitedVec}); + std.log.debug("initedVec: {}", .{initedVec}); + std.log.debug("defaultInited: {}", .{defaultInitedVec}); + +} + +// Packed structs + +const WindowFlags = packed struct { + windowed: bool = false, + maximized: bool = false, + autoResizeable: bool = false, +}; + +fn demoPackedStruct() void { + var flags = WindowFlags{}; + + flags.autoResizeable = true; + + const maximizedPtr = &flags.maximized; + + //@compileLog("bit pointer type is: ", @TypeOf(maximizedPtr)); + std.log.info("bit pointer type is: {}", .{@TypeOf(maximizedPtr)}); +} + +// File is struct + +fn demoFileIsStruct() void { + const Other = @import("other.zig"); + const o = Other{ .member = 42 }; + + std.log.info("Other type: pi: {}, .member: {}", .{Other.pi, o.member}); +} + +// SIMD vectors + +fn demoVectors() void { + const vec = @Vector(3, f32){3,2,1}; + + var vec2 = @Vector(3, f32){1,2,3}; + + const vec3 = vec + vec2; + std.log.info("vec sum is: {}", .{vec3}); + + // index + vec2[0] = 3; + + // loop through by casting to array + var vec2arr: [3]f32 = vec2; + + for (&vec2arr) |*f| { + f.* = 12.4; } + + vec2 = vec2arr; } // Comptime generics fn Optional(comptime T: type) type { return struct { + exists: bool = false, value: T, - exists: bool, }; } +fn demoComptimeGenerics() void { + const optInt = Optional(i32){ + .exists = true, + .value = 5, + }; + + const optVector2D = Optional(Vector2D){ + .exists = true, + .value = .{ .x = 1, .y = 2 }, + }; + + std.log.info("opt int value: {}, vec value: {}", .{optInt.value, optVector2D.value}); +} + +// anytype + +fn add(a: anytype, b: anytype) @TypeOf(a + b) { + return a + b; +} + +fn demoAnytype() void { + std.log.info("- DEMO: anytype", .{}); + const a = add(3, 2); // will be comptime_int + std.log.info("add integers: {}, type: {}", .{a, @TypeOf(a)}); + const f = add(34.32, 1.3); // will be comptime_float + std.log.info("add floats: {}, type: {}", .{f, @TypeOf(f)}); + + const f2 = add(@as(f32, 34.32), 1.3); // will be f32 + std.log.info("add floats: {}, type: {}", .{f2, @TypeOf(f2)}); + + var f3: f32 = 0; + f3 = add(2.3, 1.3); // will be f32 + std.log.info("add floats: {}, type: {}", .{f3, @TypeOf(f3)}); +} + +// Error unions + +const DivisionError = error { + DivideByZero, +}; + +fn divide(a: f32, b: f32) !f32 { + if (b == 0) { + return DivisionError.DivideByZero; + } else { + return a / b; + } +} + +fn demoErrorUnions() !void { + const result1 = try divide(6, 2); // No error + const result2 = divide(4, 0) catch 0; // Error! Explicitly catch with 0 + + // Get the value and handle each error: + + if (divide(3, 0)) |value| { + std.log.info("The value is: {}", .{value}); + } + else |err| switch (err) { + error.DivideByZero => std.log.debug("Oh no, it's division by zero!", .{}), + } + + std.log.debug("{} {}", .{result1, result2}); +} + +// Optionals + +fn demoOptionals() void { + var vec: ?Vector2D = null; + + if (vec) |vecValue| { + std.log.info("vec: {}", .{vecValue}); + } + + vec = .{.x = 4, .y = 3}; + + if (vec) |vecValue| { + std.log.info("vec: {}", .{vecValue}); + } + + const otherVec = vec orelse Vector2D{}; // if null, set to default + + std.log.info("vec: {}", .{otherVec}); + + var num: i32 = 3; + var optionalPointer: ?*i32 = null; // Optional pointers take no extra space + optionalPointer = # + optionalPointer.?.* = 5; // Set optional pointer value +} + // Tagged unions -const Person = struct { +const Human = struct { name: []const u8, + + // an example of "polymorphic" function that all types have: + fn say() void { + std.log.info("Yo!", .{}); + } }; const Horse = struct { - canRide: bool = false, - rider: ?*const Person = null, + rider: ?*const Human = null, + + fn say() void { + std.log.info("Njiiiii!", .{}); + } }; const Duck = struct { - friend: ?*Animal = null, - gone: bool = false, + friend: ?*Animal = null, // only ducks can have friends! + + fn say() void { + std.log.info("Quack!", .{}); + } }; const AnimalType = enum { Horse, Duck, - Person, + Human, }; const Animal = union(AnimalType) { Horse: Horse, Duck: Duck, - Person: Person, + Human: Human, + + fn say(self: Animal) void { + switch (self) { + inline else => |case| @TypeOf(case).say(), + } + + // ^ this, is equivalent to this: + + // switch (self) { + // .Horse => Horse.say(), + // .Human => Human.say(), + // .Duck => Duck.say(), + // } + } }; -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - const alloc = gpa.allocator(); - defer _ = gpa.deinit(); +fn demoTaggedUnions() void { + var horseAnimal = Animal{ .Horse = .{} }; - var list = std.ArrayList(i32).init(alloc); - defer list.deinit(); - try list.append(324); - try list.append(456); + const person = Human{ .name = "Ivan" }; - for (list.items) |item| { - std.log.debug("item: {}", .{item}); + // You can check which animal it is in if: + + if (horseAnimal == .Horse) { + horseAnimal.Horse.rider = &person; } - var animal = Animal{ .Horse = .{ .canRide = true } }; + // or switch: - const person = Person{ .name = "Dragutin" }; - - if (animal == .Horse) { - animal.Horse.rider = &person; - } - - switch (animal) { + switch (horseAnimal) { .Horse => |*horse| horse.rider = &person, else => {}, } - var personAnimal = Animal{ .Person = .{ .name = "Aleksa" } }; + var personAnimal = Animal{ .Human = .{ .name = "Hugo" } }; - var duck = Duck{ .friend = &personAnimal }; + const duck = Duck{ .friend = &personAnimal }; - duck.gone = true; + std.log.debug("Rider name: {s}", .{if (horseAnimal.Horse.rider) |rider| rider.name else "none"}); - std.log.debug("Rider name: {s}", .{if (animal.Horse.rider) |rider| rider.name else "none"}); + @TypeOf(duck).say(); + + horseAnimal.say(); } + +// Allocators + +fn demoAllocators() !void { + + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const alloc = gpa.allocator(); + defer _ = gpa.deinit(); + + // Uncomment these lines to use stack memory instead: + // var buffer: [1024]u8 = undefined; + // var fba = std.heap.FixedBufferAllocator.init(&buffer); + // const alloc = fba.allocator(); + + var list = std.ArrayList(i32).init(alloc); + defer list.deinit(); // Comment this line and see the gpa fail + + try list.append(3); + try list.append(456); + try list.append(656); + + for (list.items, 0..) |item, i| { + std.log.info("item {}: {}", .{i, item}); + } + +} + +pub fn main() !void { + std.debug.print("All your {s} are belong to us.\n", .{"codebase"}); + + demoIntegers(); + demoArrays(); + demoStruct(); + demoPackedStruct(); + demoFileIsStruct(); + demoVectors(); + demoComptimeGenerics(); + demoAnytype(); + try demoErrorUnions(); // Errors propagate up so we need to try + demoOptionals(); + demoTaggedUnions(); + try demoAllocators(); +} \ No newline at end of file diff --git a/src/other.zig b/src/other.zig index 69ebfba..555028e 100644 --- a/src/other.zig +++ b/src/other.zig @@ -1,9 +1,12 @@ const main = @import("main.zig"); +member: i32, + +// Must be pub to be available to other files pub const pi = 3.14; -pub fn add() i32 { +pub fn infiniteLoop() i32 { try main.main(); - return 3; + return 0; }