065_builtins2.zig 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. //
  2. // Zig has builtins for mathematical operations such as...
  3. //
  4. // @sqrt @sin @cos
  5. // @exp @log @floor
  6. //
  7. // ...and lots of type casting operations such as...
  8. //
  9. // @as @intToError @intToFloat
  10. // @intToPtr @ptrToInt @enumToInt
  11. //
  12. // Spending part of a rainy day skimming through the complete
  13. // list of builtins in the official Zig documentation wouldn't be
  14. // a bad use of your time. There are some seriously cool features
  15. // in there. Check out @call, @compileLog, @embedFile, and @src!
  16. //
  17. // ...
  18. //
  19. // For now, we're going to complete our examination of builtins
  20. // by exploring just THREE of Zig's MANY introspection abilities:
  21. //
  22. // 1. @This() type
  23. //
  24. // Returns the innermost struct, enum, or union that a function
  25. // call is inside.
  26. //
  27. // 2. @typeInfo(comptime T: type) @import("std").builtin.TypeInfo
  28. //
  29. // Returns information about any type in a TypeInfo union which
  30. // will contain different information depending on which type
  31. // you're examining.
  32. //
  33. // 3. @TypeOf(...) type
  34. //
  35. // Returns the type common to all input parameters (each of which
  36. // may be any expression). The type is resolved using the same
  37. // "peer type resolution" process the compiler itself uses when
  38. // inferring types.
  39. //
  40. // (Notice how the two functions which return types start with
  41. // uppercase letters? This is a standard naming practice in Zig.)
  42. //
  43. const print = @import("std").debug.print;
  44. const Narcissus = struct {
  45. me: *Narcissus = undefined,
  46. myself: *Narcissus = undefined,
  47. echo: void = undefined, // Alas, poor Echo!
  48. fn fetchTheMostBeautifulType() type {
  49. return @This();
  50. }
  51. };
  52. pub fn main() void {
  53. var narcissus: Narcissus = Narcissus{};
  54. // Oops! We cannot leave the 'me' and 'myself' fields
  55. // undefined. Please set them here:
  56. narcissus.me = &narcissus;
  57. narcissus.??? = ???;
  58. // This determines a "peer type" from three separate
  59. // references (they just happen to all be the same object).
  60. const Type1 = @TypeOf(narcissus, narcissus.me.*, narcissus.myself.*);
  61. // Oh dear, we seem to have done something wrong when calling
  62. // this function. We called it as a method, which would work
  63. // if it had a self parameter. But it doesn't. (See above.)
  64. //
  65. // The fix for this is very subtle, but it makes a big
  66. // difference!
  67. const Type2 = narcissus.fetchTheMostBeautifulType();
  68. // Now we print a pithy statement about Narcissus.
  69. print("A {s} loves all {s}es. ", .{
  70. maximumNarcissism(Type1),
  71. maximumNarcissism(Type2),
  72. });
  73. // His final words as he was looking in
  74. // those waters he habitually watched
  75. // were these:
  76. // "Alas, my beloved boy, in vain!"
  77. // The place gave every word back in reply.
  78. // He cried:
  79. // "Farewell."
  80. // And Echo called:
  81. // "Farewell!"
  82. //
  83. // --Ovid, The Metamorphoses
  84. // translated by Ian Johnston
  85. print("He has room in his heart for:", .{});
  86. // A StructFields array
  87. const fields = @typeInfo(Narcissus).Struct.fields;
  88. // 'fields' is a slice of StructFields. Here's the declaration:
  89. //
  90. // pub const StructField = struct {
  91. // name: []const u8,
  92. // type: type,
  93. // default_value: anytype,
  94. // is_comptime: bool,
  95. // alignment: comptime_int,
  96. // };
  97. //
  98. // Please complete these 'if' statements so that the field
  99. // name will not be printed if the field is of type 'void'
  100. // (which is a zero-bit type that takes up no space at all!):
  101. if (fields[0].??? != void) {
  102. print(" {s}", .{@typeInfo(Narcissus).Struct.fields[0].name});
  103. }
  104. if (fields[1].??? != void) {
  105. print(" {s}", .{@typeInfo(Narcissus).Struct.fields[1].name});
  106. }
  107. if (fields[2].??? != void) {
  108. print(" {s}", .{@typeInfo(Narcissus).Struct.fields[2].name});
  109. }
  110. // Yuck, look at all that repeated code above! I don't know
  111. // about you, but it makes me itchy.
  112. //
  113. // Alas, we can't use a regular 'for' loop here because
  114. // 'fields' can only be evaluated at compile time. It seems
  115. // like we're overdue to learn about this "comptime" stuff,
  116. // doesn't it? Don't worry, we'll get there.
  117. print(".\n", .{});
  118. }
  119. // NOTE: This exercise did not originally include the function below.
  120. // But a change after Zig 0.10.0 added the source file name to the
  121. // type. "Narcissus" became "065_builtins2.Narcissus".
  122. //
  123. // To fix this, I've added this function to strip the filename from
  124. // the front of the type name in the dumbest way possible. (It returns
  125. // a slice of the type name starting at character 14 (assuming
  126. // single-byte characters).
  127. //
  128. // We'll be seeing @typeName again in Exercise 070. For now, you can
  129. // see that it takes a Type and returns a u8 "string".
  130. fn maximumNarcissism(myType: anytype) []const u8 {
  131. // Turn '065_builtins2.Narcissus' into 'Narcissus'
  132. return @typeName(myType)[14..];
  133. }