diff --git a/doc/langref.html.in b/doc/langref.html.in index 7c1f9b53d9e6..f1ae2bafaa44 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1651,7 +1651,7 @@ fn foo(bytes: []u8) u32 {
@ptrCast(*u32, f32(12.34)).*

Instead, use {#link|@bitCast#}:

@bitCast(u32, f32(12.34))
-

As an added benefit, the @bitcast version works at compile-time.

+

As an added benefit, the @bitCast version works at compile-time.

{#see_also|Slices|Memory#} {#header_close#} {#header_close#} @@ -3551,13 +3551,91 @@ const optional_value: ?i32 = null;

TODO: ptrcast builtin

TODO: explain number literals vs concrete types

{#header_close#} + {#header_open|void#} -

TODO: assigning void has no codegen

-

TODO: hashmap with void becomes a set

-

TODO: difference between c_void and void

-

TODO: void is the default return value of functions

-

TODO: functions require assigning the return value

+

+ void represents a type that has no value. Code that makes use of void values is + not included in the final generated code: +

+ {#code_begin|syntax#} +export fn entry() void { + var x: void = {}; + var y: void = {}; + x = y; +} + {#code_end#} +

When this turns into LLVM IR, there is no code generated in the body of entry, + even in debug mode. For example, on x86_64:

+
0000000000000010 <entry>:
+  10:	55                   	push   %rbp
+  11:	48 89 e5             	mov    %rsp,%rbp
+  14:	5d                   	pop    %rbp
+  15:	c3                   	retq   
+

These assembly instructions do not have any code associated with the void values - + they only perform the function call prologue and epilog.

+

+ void can be useful for instantiating generic types. For example, given a + Map(Key, Value), one can pass void for the Value + type to make it into a Set: +

+ {#code_begin|test#} +const std = @import("std"); +const assert = std.debug.assert; + +test "turn HashMap into a set with void" { + var map = std.HashMap(i32, void, hash_i32, eql_i32).init(std.debug.global_allocator); + defer map.deinit(); + + _ = try map.put(1, {}); + _ = try map.put(2, {}); + + assert(map.contains(2)); + assert(!map.contains(3)); + + _ = map.remove(2); + assert(!map.contains(2)); +} + +fn hash_i32(x: i32) u32 { + return @bitCast(u32, x); +} + +fn eql_i32(a: i32, b: i32) bool { + return a == b; +} + {#code_end#} +

Note that this is different than using a dummy value for the hash map value. + By using void as the type of the value, the hash map entry type has no value field, and + thus the hash map takes up less space. Further, all the code that deals with storing and loading the + value is deleted, as seen above. +

+

+ void is distinct from c_void, which is defined like this: + pub const c_void = @OpaqueType();. + void has a known size of 0 bytes, and c_void has an unknown, but non-zero, size. +

+

+ Expressions of type void are the only ones whose value can be ignored. For example: +

+ {#code_begin|test_err|expression value is ignored#} +test "ignoring expression value" { + foo(); +} + +fn foo() i32 { + return 1234; +} + {#code_end#} +

However, if the expression has type void:

+ {#code_begin|test#} +test "ignoring expression value" { + foo(); +} + +fn foo() void {} + {#code_end#} {#header_close#} + {#header_open|this#}

TODO: example of this referring to Self struct

TODO: example of this referring to recursion function