From 618eade1e625f99364f1cde26e79d37eb1eb4040 Mon Sep 17 00:00:00 2001 From: Dave Gauer Date: Wed, 21 Apr 2021 20:08:34 -0400 Subject: add ex070 comptime 5 --- exercises/070_comptime5.zig | 135 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 exercises/070_comptime5.zig (limited to 'exercises/070_comptime5.zig') diff --git a/exercises/070_comptime5.zig b/exercises/070_comptime5.zig new file mode 100644 index 0000000..7934326 --- /dev/null +++ b/exercises/070_comptime5.zig @@ -0,0 +1,135 @@ +// +// Being able to pass types to functions at compile time lets us +// generate code that works with multiple types. But it doesn't +// help us pass VALUES of different types to a function. +// +// For that, we have the 'anytype' placeholder, which tells Zig +// to infer the actual type of a parameter at compile time. +// +// fn foo(thing: anytype) void { ... } +// +// Then we can use builtins such as @TypeOf(), @typeInfo(), +// @typeName(), @hasDecl(), and @hasField() to determine more +// about the type that has been passed in. All of this logic will +// be performed entirely at compile time. +// +const print = @import("std").debug.print; + +// Let's define three structs: Duck, RubberDuck, and Duct. Notice +// that Duck and RubberDuck both contain waddle() and quack() +// methods declared in their namespace (also known as "decls"). + +const Duck = struct { + eggs: u8, + loudness: u8, + location_x: i32 = 0, + location_y: i32 = 0, + + fn waddle(self: Duck, x: i16, y: i16) void { + self.location_x += x; + self.location_y += y; + } + + fn quack(self: Duck) void { + if (self.loudness < 4) { + print("\"Quack.\" ", .{}); + } else { + print("\"QUACK!\" ", .{}); + } + } +}; + +const RubberDuck = struct { + in_bath: bool = false, + location_x: i32 = 0, + location_y: i32 = 0, + + fn waddle(self: RubberDuck, x: i16, y: i16) void { + self.location_x += x; + self.location_y += y; + } + + fn quack(self: RubberDuck) void { + print("\"Squeek!\" ", .{}); + } +}; + +const Duct = struct { + diameter: u32, + length: u32, + galvanized: bool, + connection: ?*Duct = null, + + fn connect(self: Duct, other: *Duct) !void { + if (self.diameter == other.diameter) { + self.connection = other; + } else { + return DuctError.UnmatchedDiameters; + } + } +}; + +const DuctError = error{UnmatchedDiameters}; + +pub fn main() void { + // This is a real duck! + const ducky1 = Duck{ + .eggs = 0, + .loudness = 3, + }; + + // This is not a real duck, but it has quack() and waddle() + // abilities, so it's still a "duck". + const ducky2 = RubberDuck{ + .in_bath = false, + }; + + // This is not even remotely a duck. + const ducky3 = Duct{ + .diameter = 17, + .length = 165, + .galvanized = true, + }; + + print("ducky1: {}, ", .{isADuck(ducky1)}); + print("ducky2: {}, ", .{isADuck(ducky2)}); + print("ducky3: {}\n", .{isADuck(ducky3)}); +} + +// This function has a single parameter which is inferred at +// compile time. It uses builtins @TypeOf() and @hasDecl() to +// perform duck typing ("if it walks like a duck and it quacks +// like a duck, then it must be a duck") to determine if the type +// is a "duck". +fn isADuck(possible_duck: anytype) bool { + // We'll use @hasDecl() to determine if the type has + // everything needed to be a "duck". + // + // In this example, 'has_increment' will be true if type Foo + // has an increment() method: + // + // const has_increment = @hasDecl(Foo, "increment"); + // + // Please make sure MyType has both waddle() and quack() + // methods: + const MyType = @TypeOf(possible_duck); + const walks_like_duck = ???; + const quacks_like_duck = ???; + + const is_duck = walks_like_duck and quacks_like_duck; + + if (is_duck) { + // We also call the quack() method here to prove that Zig + // allows us to perform duck actions on anything + // sufficiently duck-like. + // + // Because all of the checking and inference is performed + // at compile time, we still have complete type safety: + // attempting to call the quack() method on a struct that + // doesn't have it (like Duct) would result in a compile + // error, not a runtime panic or crash! + possible_duck.quack(); + } + + return is_duck; +} -- cgit v1.2.3-ZIG