about summary refs log tree commit diff
path: root/lang/zig/fn.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lang/zig/fn.zig')
-rw-r--r--lang/zig/fn.zig78
1 files changed, 78 insertions, 0 deletions
diff --git a/lang/zig/fn.zig b/lang/zig/fn.zig
new file mode 100644
index 0000000..0fb3002
--- /dev/null
+++ b/lang/zig/fn.zig
@@ -0,0 +1,78 @@
+const expect = @import("std").testing.expect;
+
+// Functions are declared like this
+fn add(a: i8, b: i8) i8 {
+    return if (a == 0) b else a + b;
+}
+
+// The export specifier makes a function externally visible in the generated
+// object file, and makes it use the C ABI.
+export fn sub(a: i8, b: i8) i8 { return a - b; }
+
+// The extern specifier is used to declare a function that will be resolved
+// at link time, when linking statically, or at runtime, when linking
+// dynamically.
+extern "c" fn atan2(a: f64, b: f64) f64;
+
+// The @setCold builtin tells the optimizer that a function is rarely called.
+fn abort() noreturn {
+    @setCold(true);
+    while (true) {}
+}
+
+// The naked calling convention makes a function not have any function prologue
+// or epilogue.  This can be useful when integrating with assembly.
+fn _start() callconv(.Naked) noreturn {
+    abort();
+}
+
+// The inline specifier forces a function to be inlined at all call sites.
+// If the function cannot be inlined, it is a compile-time error.
+inline fn shiftLeftOne(a: u32) u32 {
+    return a << 1;
+}
+
+// The pub specifier allows the function to be visible when importing.
+// Another file can use @import and call sub2
+pub fn sub2(a: i8, b: i8) i8 { return a - b; }
+
+// Functions can be used as values and are equivalent to pointers.
+fn do_op(fn_call: fn (a: i8, b: i8) i8, op1: i8, op2: i8) i8 {
+    return fn_call(op1, op2);
+}
+
+test "function" {
+    expect(do_op(add, 5, 6) == 11);
+    expect(do_op(sub2, 5, 6) == -1);
+}
+
+const Point = struct { x: i32, y: i32 };
+
+fn foo(point: Point) i32 {
+    // Here, `point` could be a reference, or a copy. The function body
+    // can ignore the difference and treat it as a value. Be very careful
+    // taking the address of the parameter - it should be treated as if
+    // the address will become invalid when the function returns.
+    return point.x + point.y;
+}
+
+test "pass struct to function" {
+    expect(foo(Point{ .x = 1, .y = 2 }) == 3);
+}
+
+fn addFortyTwo(x: anytype) @TypeOf(x) {
+    return x + 42;
+}
+
+test "fn type inference" {
+    expect(addFortyTwo(1) == 43);
+    expect(@TypeOf(addFortyTwo(1)) == comptime_int);
+    const y: i64 = 2;
+    expect(addFortyTwo(y) == 44);
+    expect(@TypeOf(addFortyTwo(y)) == i64);
+}
+
+test "fn reflection" {
+    expect(@typeInfo(@TypeOf(expect)).Fn.return_type.? == void);
+    expect(@typeInfo(@TypeOf(expect)).Fn.is_var_args == false);
+}