123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- //
- // Zig has builtins for mathematical operations such as...
- //
- // @sqrt @sin @cos
- // @exp @log @floor
- //
- // ...and lots of type casting operations such as...
- //
- // @as @errorFromInt @floatFromInt
- // @ptrFromInt @intFromPtr @intFromEnum
- //
- // 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.Type
- //
- // Returns information about any type in a data structure 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;
- const Narcissus = struct {
- me: *Narcissus = undefined,
- myself: *Narcissus = undefined,
- echo: void = undefined, // Alas, poor Echo!
- 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.me = &narcissus;
- narcissus.??? = ???;
- // This determines a "peer type" from three separate
- // references (they just happen to all be the same object).
- const Type1 = @TypeOf(narcissus, narcissus.me.*, narcissus.myself.*);
- // Oh dear, we seem to have done something wrong when calling
- // this function. We called it as a method, which would work
- // if it had a self parameter. But it doesn't. (See above.)
- //
- // The fix for this is very subtle, but it makes a big
- // difference!
- const Type2 = narcissus.fetchTheMostBeautifulType();
- // Now we print a pithy statement about Narcissus.
- print("A {s} loves all {s}es. ", .{
- maximumNarcissism(Type1),
- maximumNarcissism(Type2),
- });
- // 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 a slice of StructFields. Here's the declaration:
- //
- // pub const StructField = struct {
- // name: []const u8,
- // 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,
- // doesn't it? Don't worry, we'll get there.
- print(".\n", .{});
- }
- // NOTE: This exercise did not originally include the function below.
- // But a change after Zig 0.10.0 added the source file name to the
- // type. "Narcissus" became "065_builtins2.Narcissus".
- //
- // To fix this, I've added this function to strip the filename from
- // the front of the type name in the dumbest way possible. (It returns
- // a slice of the type name starting at character 14 (assuming
- // single-byte characters).
- //
- // We'll be seeing @typeName again in Exercise 070. For now, you can
- // see that it takes a Type and returns a u8 "string".
- fn maximumNarcissism(myType: anytype) []const u8 {
- // Turn '065_builtins2.Narcissus' into 'Narcissus'
- return @typeName(myType)[14..];
- }
|