authorgravatar for pat.github@tullmann.orgPat Tullmann <pat.github@tullmann.org> 2023-09-21 07:50:48-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-09-21 17:50:48+03:00
log00f42909adf23a92905aa7211d74ed5b5397b397
tree806d6e6e1b28bf508d4af3b7042f57b6047c77b9
parentc481510c99ab29903350a834810bdcac32dbd9ea
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

langref: small fixes to wording and examples

Simplify wording and add some formatting in several locations. Expand sentinel array tests to highlight (non-)handling of internal sentinels. Fix format of symbol names in function pointers example. Clarify wording a bit on the builin atomic* documentation. Remove the (second) builtin compileLog example that demonstrated a lack of compileLog entries. * langref: address comments from rohlem Use "0-terminated" instead of "null-terminated". Undo some changes that were not as clear an improvement as I though. * langref: remove stray "&#14;" Thanks to rohlem for spotting this typo.

1 files changed, 56 insertions(+), 62 deletions(-)

doc/langref.html.in+56-62
......@@ -2523,19 +2523,28 @@ test "multidimensional arrays" {
25232523 {#header_open|Sentinel-Terminated Arrays#}
25242524 <p>
25252525 The syntax {#syntax#}[N:x]T{#endsyntax#} describes an array which has a sentinel element of value {#syntax#}x{#endsyntax#} at the
2526 index corresponding to {#syntax#}len{#endsyntax#}.
2526 index corresponding to the length {#syntax#}N{#endsyntax#}.
25272527 </p>
25282528 {#code_begin|test|test_null_terminated_array#}
25292529const std = @import("std");
25302530const expect = std.testing.expect;
25312531
2532test "null terminated array" {
2532test "0-terminated sentinel array" {
25332533 const array = [_:0]u8 {1, 2, 3, 4};
25342534
25352535 try expect(@TypeOf(array) == [4:0]u8);
25362536 try expect(array.len == 4);
25372537 try expect(array[4] == 0);
25382538}
2539
2540test "extra 0s in 0-terminated sentinel array" {
2541 // The sentinel value may appear earlier, but does not influence the compile-time 'len'.
2542 const array = [_:0]u8 {1, 0, 0, 4};
2543
2544 try expect(@TypeOf(array) == [4:0]u8);
2545 try expect(array.len == 4);
2546 try expect(array[4] == 0);
2547}
25392548 {#code_end#}
25402549 {#see_also|Sentinel-Terminated Pointers|Sentinel-Terminated Slices#}
25412550 {#header_close#}
......@@ -3052,8 +3061,6 @@ test "using slices for strings" {
30523061}
30533062
30543063test "slice pointer" {
3055 var a: []u8 = undefined;
3056 try expect(@TypeOf(a) == []u8);
30573064 var array: [10]u8 = undefined;
30583065 const ptr = &array;
30593066 try expect(@TypeOf(ptr) == *[10]u8);
......@@ -3062,10 +3069,10 @@ test "slice pointer" {
30623069 var start: usize = 0;
30633070 var end: usize = 5;
30643071 const slice = ptr[start..end];
3065 slice[2] = 3;
3066 try expect(slice[2] == 3);
30673072 // The slice is mutable because we sliced a mutable pointer.
30683073 try expect(@TypeOf(slice) == []u8);
3074 slice[2] = 3;
3075 try expect(array[2] == 3);
30693076
30703077 // Again, slicing with comptime-known indexes will produce another pointer
30713078 // to an array:
......@@ -3088,7 +3095,7 @@ test "slice pointer" {
30883095const std = @import("std");
30893096const expect = std.testing.expect;
30903097
3091test "null terminated slice" {
3098test "0-terminated slice" {
30923099 const slice: [:0]const u8 = "hello";
30933100
30943101 try expect(slice.len == 5);
......@@ -3104,7 +3111,7 @@ test "null terminated slice" {
31043111const std = @import("std");
31053112const expect = std.testing.expect;
31063113
3107test "null terminated slicing" {
3114test "0-terminated slicing" {
31083115 var array = [_]u8{ 3, 2, 1, 0, 3, 2, 1, 0 };
31093116 var runtime_length: usize = 3;
31103117 const slice = array[0..runtime_length :0];
......@@ -3590,7 +3597,7 @@ const std = @import("std");
35903597const expect = std.testing.expect;
35913598
35923599test "fully anonymous struct" {
3593 try dump(.{
3600 try check(.{
35943601 .int = @as(u32, 1234),
35953602 .float = @as(f64, 12.34),
35963603 .b = true,
......@@ -3598,7 +3605,7 @@ test "fully anonymous struct" {
35983605 });
35993606}
36003607
3601fn dump(args: anytype) !void {
3608fn check(args: anytype) !void {
36023609 try expect(args.int == 1234);
36033610 try expect(args.float == 12.34);
36043611 try expect(args.b);
......@@ -3813,8 +3820,8 @@ test "switch using enum literals" {
38133820
38143821 {#header_open|Non-exhaustive enum#}
38153822 <p>
3816 A Non-exhaustive enum can be created by adding a trailing '_' field.
3817 It must specify a tag type and cannot consume every enumeration value.
3823 A non-exhaustive enum can be created by adding a trailing {#syntax#}_{#endsyntax#} field.
3824 The enum must specify a tag type and cannot consume every enumeration value.
38183825 </p>
38193826 <p>
38203827 {#link|@enumFromInt#} on a non-exhaustive enum involves the safety semantics
......@@ -3822,8 +3829,8 @@ test "switch using enum literals" {
38223829 a well-defined enum value.
38233830 </p>
38243831 <p>
3825 A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong
3826 with the difference being that it makes it a compile error if all the known tag names are not handled by the switch.
3832 A switch on a non-exhaustive enum can include a {#syntax#}_{#endsyntax#} prong as an alternative to an {#syntax#}else{#endsyntax#} prong.
3833 With a {#syntax#}_{#endsyntax#} prong the compiler errors if all the known tag names are not handled by the switch.
38273834 </p>
38283835 {#code_begin|test|test_switch_non-exhaustive#}
38293836const std = @import("std");
......@@ -5268,14 +5275,14 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 {
52685275pub fn sub2(a: i8, b: i8) i8 { return a - b; }
52695276
52705277// Function pointers are prefixed with `*const `.
5271const call2_op = *const fn (a: i8, b: i8) i8;
5272fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 {
5273 return fn_call(op1, op2);
5278const Call2Op = *const fn (a: i8, b: i8) i8;
5279fn doOp(fnCall: Call2Op, op1: i8, op2: i8) i8 {
5280 return fnCall(op1, op2);
52745281}
52755282
52765283test "function" {
5277 try expect(do_op(add, 5, 6) == 11);
5278 try expect(do_op(sub2, 5, 6) == -1);
5284 try expect(doOp(add, 5, 6) == 11);
5285 try expect(doOp(sub2, 5, 6) == -1);
52795286}
52805287 {#code_end#}
52815288 <p>There is a difference between a function <em>body</em> and a function <em>pointer</em>.
......@@ -6515,7 +6522,7 @@ test "coerce to optionals" {
65156522 try expect(y == null);
65166523}
65176524 {#code_end#}
6518 <p>It works nested inside the {#link|Error Union Type#}, too:</p>
6525 <p>Optionals work nested inside the {#link|Error Union Type#}, too:</p>
65196526 {#code_begin|test|test_coerce_optional_wrapped_error_union#}
65206527const std = @import("std");
65216528const expect = std.testing.expect;
......@@ -6841,7 +6848,8 @@ test "turn HashMap into a set with void" {
68416848 {#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}anyopaque{#endsyntax#} has an unknown, but non-zero, size.
68426849 </p>
68436850 <p>
6844 Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example:
6851 Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example, ignoring
6852 a non-{#syntax#}void{#endsyntax#} expression is a compile error:
68456853 </p>
68466854 {#code_begin|test_err|test_expression_ignored|ignored#}
68476855test "ignoring expression value" {
......@@ -6852,7 +6860,7 @@ fn foo() i32 {
68526860 return 1234;
68536861}
68546862 {#code_end#}
6855 <p>However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Function return values can also be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}. </p>
6863 <p>However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Expression results can be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}. </p>
68566864 {#code_begin|test|test_void_ignored#}
68576865test "void is ignored" {
68586866 returnsVoid();
......@@ -7110,12 +7118,10 @@ fn performFn(start_value: i32) i32 {
71107118}
71117119 {#end_syntax_block#}
71127120 <p>
7113 Note that this happens even in a debug build; in a release build these generated functions still
7114 pass through rigorous LLVM optimizations. The important thing to note, however, is not that this
7115 is a way to write more optimized code, but that it is a way to make sure that what <em>should</em> happen
7116 at compile-time, <em>does</em> happen at compile-time. This catches more errors and as demonstrated
7117 later in this article, allows expressiveness that in other languages requires using macros,
7118 generated code, or a preprocessor to accomplish.
7121 Note that this happens even in a debug build.
7122 This is not a way to write more optimized code, but it is a way to make sure that what <em>should</em> happen
7123 at compile-time, <em>does</em> happen at compile-time. This catches more errors and allows expressiveness
7124 that in other languages requires using macros, generated code, or a preprocessor to accomplish.
71197125 </p>
71207126 {#header_close#}
71217127 {#header_open|Compile-Time Expressions#}
......@@ -7297,9 +7303,8 @@ test "variable values" {
72977303 {#header_close#}
72987304 {#header_open|Generic Data Structures#}
72997305 <p>
7300 Zig uses these capabilities to implement generic data structures without introducing any
7301 special-case syntax. If you followed along so far, you may already know how to create a
7302 generic data structure.
7306 Zig uses comptime capabilities to implement generic data structures without introducing any
7307 special-case syntax.
73037308 </p>
73047309 <p>
73057310 Here is an example of a generic {#syntax#}List{#endsyntax#} data structure.
......@@ -7321,7 +7326,6 @@ var list = List(i32){
73217326 {#code_end#}
73227327 <p>
73237328 That's it. It's a function that returns an anonymous {#syntax#}struct{#endsyntax#}.
7324 To keep the language small and uniform, all aggregate types in Zig are anonymous.
73257329 For the purposes of error messages and debugging, Zig infers the name
73267330 {#syntax#}"List(i32)"{#endsyntax#} from the function name and parameters invoked when creating
73277331 the anonymous struct.
......@@ -7754,6 +7758,9 @@ test "global assembly" {
77547758 <p>TODO: @fence()</p>
77557759 <p>TODO: @atomic rmw</p>
77567760 <p>TODO: builtin atomic memory ordering enum</p>
7761
7762 {#see_also|@atomicLoad|@atomicStore|@atomicRmw|@fence|@cmpxchgWeak|@cmpxchgStrong#}
7763
77577764 {#header_close#}
77587765
77597766 {#header_open|Async Functions#}
......@@ -7824,7 +7831,7 @@ comptime {
78247831 {#header_open|@atomicLoad#}
78257832 <pre>{#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre>
78267833 <p>
7827 This builtin function atomically dereferences a pointer and returns the value.
7834 This builtin function atomically dereferences a pointer to a {#syntax#}T{#endsyntax#} and returns the value.
78287835 </p>
78297836 <p>
78307837 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
......@@ -7836,14 +7843,15 @@ comptime {
78367843 {#header_open|@atomicRmw#}
78377844 <pre>{#syntax#}@atomicRmw(comptime T: type, ptr: *T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre>
78387845 <p>
7839 This builtin function atomically modifies memory and then returns the previous value.
7846 This builtin function dereferences a pointer to a {#syntax#}T{#endsyntax#} and atomically
7847 modifies the value and returns the previous value.
78407848 </p>
78417849 <p>
78427850 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
78437851 an integer or an enum.
78447852 </p>
78457853 <p>
7846 Supported operations:
7854 Supported values for the {#syntax#}op{#endsyntax#} parameter:
78477855 </p>
78487856 <ul>
78497857 <li>{#syntax#}.Xchg{#endsyntax#} - stores the operand unmodified. Supports enums, integers and floats.</li>
......@@ -7864,7 +7872,7 @@ comptime {
78647872 {#header_open|@atomicStore#}
78657873 <pre>{#syntax#}@atomicStore(comptime T: type, ptr: *T, value: T, comptime ordering: builtin.AtomicOrder) void{#endsyntax#}</pre>
78667874 <p>
7867 This builtin function atomically stores a value.
7875 This builtin function dereferences a pointer to a {#syntax#}T{#endsyntax#} and atomically stores the given value.
78687876 </p>
78697877 <p>
78707878 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
......@@ -8122,7 +8130,8 @@ pub const CallModifier = enum {
81228130 {#header_open|@cmpxchgStrong#}
81238131 <pre>{#syntax#}@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}</pre>
81248132 <p>
8125 This function performs a strong atomic compare exchange operation. It's the equivalent of this code,
8133 This function performs a strong atomic compare-and-exchange operation, returning {#syntax#}null{#endsyntax#}
8134 if the current value is not the given expected value. It's the equivalent of this code,
81268135 except atomic:
81278136 </p>
81288137 {#code_begin|syntax|not_atomic_cmpxchgStrong#}
......@@ -8137,7 +8146,7 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v
81378146}
81388147 {#code_end#}
81398148 <p>
8140 If you are using cmpxchg in a loop, {#link|@cmpxchgWeak#} is the better choice, because it can be implemented
8149 If you are using cmpxchg in a retry loop, {#link|@cmpxchgWeak#} is the better choice, because it can be implemented
81418150 more efficiently in machine instructions.
81428151 </p>
81438152 <p>
......@@ -8151,7 +8160,8 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v
81518160 {#header_open|@cmpxchgWeak#}
81528161 <pre>{#syntax#}@cmpxchgWeak(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}</pre>
81538162 <p>
8154 This function performs a weak atomic compare exchange operation. It's the equivalent of this code,
8163 This function performs a weak atomic compare-and-exchange operation, returning {#syntax#}null{#endsyntax#}
8164 if the current value is not the given expected value. It's the equivalent of this code,
81558165 except atomic:
81568166 </p>
81578167 {#syntax_block|zig|cmpxchgWeakButNotAtomic#}
......@@ -8166,7 +8176,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
81668176}
81678177 {#end_syntax_block#}
81688178 <p>
8169 If you are using cmpxchg in a loop, the sporadic failure will be no problem, and {#syntax#}cmpxchgWeak{#endsyntax#}
8179 If you are using cmpxchg in a retry loop, the sporadic failure will be no problem, and {#syntax#}cmpxchgWeak{#endsyntax#}
81708180 is the better choice, because it can be implemented more efficiently in machine instructions.
81718181 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
81728182 </p>
......@@ -8219,24 +8229,6 @@ const num1 = blk: {
82198229test "main" {
82208230 @compileLog("comptime in main");
82218231
8222 print("Runtime in main, num1 = {}.\n", .{num1});
8223}
8224 {#code_end#}
8225 <p>
8226 If all {#syntax#}@compileLog{#endsyntax#} calls are removed or
8227 not encountered by analysis, the
8228 program compiles successfully and the generated executable prints:
8229 </p>
8230 {#code_begin|test|test_without_compileLog_builtin#}
8231const print = @import("std").debug.print;
8232
8233const num1 = blk: {
8234 var val1: i32 = 99;
8235 val1 = val1 + 1;
8236 break :blk val1;
8237};
8238
8239test "main" {
82408232 print("Runtime in main, num1 = {}.\n", .{num1});
82418233}
82428234 {#code_end#}
......@@ -9020,14 +9012,16 @@ pub const PrefetchOptions = struct {
90209012 {#header_open|@setCold#}
90219013 <pre>{#syntax#}@setCold(comptime is_cold: bool) void{#endsyntax#}</pre>
90229014 <p>
9023 Tells the optimizer that a function is rarely called.
9015 Tells the optimizer that the current function is (or is not) rarely called.
9016
9017 This function is only valid within function scope.
90249018 </p>
90259019 {#header_close#}
90269020
90279021 {#header_open|@setEvalBranchQuota#}
90289022 <pre>{#syntax#}@setEvalBranchQuota(comptime new_quota: u32) void{#endsyntax#}</pre>
90299023 <p>
9030 Changes the maximum number of backwards branches that compile-time code
9024 Increase the maximum number of backwards branches that compile-time code
90319025 execution can use before giving up and making a compile error.
90329026 </p>
90339027 <p>
......@@ -9232,7 +9226,7 @@ test "vector @shuffle" {
92329226 The result is a target-specific compile time constant.
92339227 </p>
92349228 <p>
9235 This size may contain padding bytes. If there were two consecutive T in memory, this would be the offset
9229 This size may contain padding bytes. If there were two consecutive T in memory, the padding would be the offset
92369230 in bytes between element at index 0 and the element at index 1. For {#link|integer|Integers#},
92379231 consider whether you want to use {#syntax#}@sizeOf(T){#endsyntax#} or
92389232 {#syntax#}@typeInfo(T).Int.bits{#endsyntax#}.
......@@ -9247,7 +9241,7 @@ test "vector @shuffle" {
92479241 {#header_open|@splat#}
92489242 <pre>{#syntax#}@splat(scalar: anytype) anytype{#endsyntax#}</pre>
92499243 <p>
9250 Produces a vector where each element is the value {#syntax#}scalar{#endsyntax#}.
9244 Produces a vector where each element is the value {#syntax#}scalar{#endsyntax#}.
92519245 The return type and thus the length of the vector is inferred.
92529246 </p>
92539247 {#code_begin|test|test_splat_builtin#}