diff --git a/build.zig b/build.zig index ebc6e7c..50fde90 100644 --- a/build.zig +++ b/build.zig @@ -317,6 +317,7 @@ const exercises = [_]Exercise{ .{ .main_file = "062_loop_expressions.zig", .output = "Current language: Zig", + .hint = "Surely the current language is 'Zig'!", }, .{ .main_file = "063_labels.zig", @@ -326,6 +327,10 @@ const exercises = [_]Exercise{ .main_file = "064_builtins.zig", .output = "1101 + 0101 = 0010 (true). Furthermore, 11110000 backwards is 00001111.", }, + .{ + .main_file = "065_builtins2.zig", + .output = "A Narcissus loves all Narcissuses. He has room in his heart for: me myself.", + }, }; /// Check the zig version to make sure it can compile the examples properly. diff --git a/exercises/065_builtins2.zig b/exercises/065_builtins2.zig new file mode 100644 index 0000000..9667b76 --- /dev/null +++ b/exercises/065_builtins2.zig @@ -0,0 +1,127 @@ +// +// Zig has builtins for mathematical operations such as... +// +// @sqrt @sin @cos +// @exp @log @floor +// +// ...and lots of type casting operations such as... +// +// @as @intToError @intToFloat +// @intToPtr @ptrToInt @enumToInt +// +// Spending part of a rainy day skimming through the complete +// list of builtins in the official Zig documentation wouldn't be +// a bad use of your time. There are some seriously cool features +// in there. Check out @call, @compileLog, @embedFile, and @src! +// +// ... +// +// For now, we're going to complete our examination of builtins +// by exploring just THREE of Zig's MANY introspection abilities: +// +// 1. @This() type +// +// Returns the innermost struct, enum, or union that a function +// call is inside. +// +// 2. @typeInfo(comptime T: type) @import("std").builtin.TypeInfo +// +// Returns information about any type in a TypeInfo union which +// will contain different information depending on which type +// you're examining. +// +// 3. @TypeOf(...) type +// +// Returns the type common to all input parameters (each of which +// may be any expression). The type is resolved using the same +// "peer type resolution" process the compiler itself uses when +// inferring types. +// +// (Notice how the two functions which return types start with +// uppercase letters? This is a standard naming practice in Zig.) +// +const print = import(std).debug.print; // Oops! + +const Narcissus = struct { + me: *Narcissus = undefined, + myself: *Narcissus = undefined, + echo: void = undefined, + + fn fetchTheMostBeautifulType() type { + return @This(); + } +}; + +pub fn main() void { + var narcissus: Narcissus = Narcissus {}; + + // Oops! We cannot leave the 'me' and 'myself' fields + // undefined. Please set them here: + ??? = &narcissus; + ??? = &narcissus; + + // This determines a "peer type" from three separate + // references (they just happen to all be the same object). + const T1 = @TypeOf(narcissus, narcissus.me.*, narcissus.myself.*); + + // Oh dear, we seem to have done something wrong when calling + // this function. It is namespaced to the struct, but doesn't + // use the method syntax (there's no self parameter). Please + // fix this call: + const T2 = narcissus.fetchTheMostBeautifulType(); + + print("A {} loves all {}es. ", .{T1, T2}); + + // His final words as he was looking in + // those waters he habitually watched + // were these: + // "Alas, my beloved boy, in vain!" + // The place gave every word back in reply. + // He cried: + // "Farewell." + // And Echo called: + // "Farewell!" + // + // --Ovid, The Metamorphoses + // translated by Ian Johnston + + print("He has room in his heart for:", .{}); + + // A StructFields array + const fields = @typeInfo(Narcissus).Struct.fields; + + // 'fields' is an array of StructFields. Here's the declaration: + // + // pub const StructField = struct { + // name: []const u8, + // field_type: type, + // default_value: anytype, + // is_comptime: bool, + // alignment: comptime_int, + // }; + // + // Please complete these 'if' statements so that the field + // name will not be printed if the field is of type 'void' + // (which is a zero-bit type that takes up no space at all!): + if (fields[0].??? != void) { + print(" {s}", .{@typeInfo(Narcissus).Struct.fields[0].name}); + } + + if (fields[1].??? != void) { + print(" {s}", .{@typeInfo(Narcissus).Struct.fields[1].name}); + } + + if (fields[2].??? != void) { + print(" {s}", .{@typeInfo(Narcissus).Struct.fields[2].name}); + } + + // Yuck, look at all that repeated code above! I don't know + // about you, but it makes me itchy. + // + // Alas, we can't use a regular 'for' loop here because + // 'fields' can only be evaluated at compile time. It seems + // like we're overdue to learn about this "comptime" stuff, + // isn't it? :-) + + print(".\n", .{}); +} diff --git a/patches/patches/065_builtins2.patch b/patches/patches/065_builtins2.patch new file mode 100644 index 0000000..1c2acf5 --- /dev/null +++ b/patches/patches/065_builtins2.patch @@ -0,0 +1,26 @@ +43c43 +< const print = import(std).debug.print; // Oops! +--- +> const print = @import("std").debug.print; +60,61c60,61 +< ??? = &narcissus; +< ??? = &narcissus; +--- +> narcissus.me = &narcissus; +> narcissus.myself = &narcissus; +71c71 +< const T2 = narcissus.fetchTheMostBeautifulType(); +--- +> const T2 = Narcissus.fetchTheMostBeautifulType(); +106c106 +< if (fields[0].??? != void) { +--- +> if (fields[0].field_type != void) { +110c110 +< if (fields[1].??? != void) { +--- +> if (fields[1].field_type != void) { +114c114 +< if (fields[2].??? != void) { +--- +> if (fields[2].field_type != void) {