4 ms·
That was a nice, clear explanation that even I could understand. One thing I wasn't sure about, though. var arr = [_]u32{ 1, 2, 3, 4, 5, 6 }; // 1, 2, 3, 4,
by Lyngbakr 3y ago
That was a nice, clear explanation that even I could understand. One thing I wasn't sure about, though.
var arr = [_]u32{ 1, 2, 3, 4, 5, 6 }; // 1, 2, 3, 4, 5, 6
const slice1 = arr[1..5]; // 2, 3, 4, 5
const slice2 = slice1[1..3];
If I were to use indices out of range, presumably that would that give me a compile time error? Could I use variables as the indices and, if so, could I get a seg fault at runtime or are there some sort of guards on there?
- ForkMeOnTinder 3y ago> If I were to use indices out of range, presumably that would that give me a compile time error? Yes, if all operands are comptime-known (or comptime-length-known), bounds checks happen eagerly at compile time. > Could I use variables as the indices and, if so, could I get a seg fault at runtime or are there some sort of guards on there? Yes you can use variables. If they're out of range, behavior depends on the build mode: - In Debug and ReleaseSafe, you get a guaranteed panic (which aborts the app with a stack trace) - In ReleaseSmall and ReleaseFast, you get undefined behavior On their discord I suggested a version of slicing that bounds checks in all modes (something like `slice?[1..5]`, syntax doesn't matter) and returns an optional slice, which is null if the bounds are out of range. But they didn't seem too keen on it. So I've been using a little wrapper function instead.
- throwawaymaths 3y agoWhy not just compile your whole program safe and then demarcate which functions you want to not be safety checked?
- estebank 3y agoCareful, you're dangerously close to suggesting an effects system. If the function explicitly marked as doing unsafe math operations calls another that doesn't specify a preference, should its math operation be safe or unsafe? If the former, this makes it likely a better default, but limiting in its usefulness. If the later, then your compiler now has to keep track of this information for the entire call graph.
- throwawaymaths 3y agoThe form of safety we are talking about here is not like rust's "safety", it does not color functions, and is strictly scoped to the compiled unit (in this case, function) https://ziglang.org/documentation/master/#setRuntimeSafety https://ziglang.org/documentation/master/#setRuntimeSafety
- estebank 3y agoI am aware, my point is about how the following is dealt with: fn foo(x: i32) i32 { return x + 100; } fn bar(x: i32) i32 { @setRuntimeSafety(false); return foo(x + 100); } Particularly when you have arbitrarily deep call graphs where some explicitly enable and disable runtime safety.
- throwawaymaths 3y agoYou mean overflow checking? It only applies to the `x + 100` in bar. Bar can still panic if the `x + 100` in foo overflows. Why should it be any other way?
- stefncb 3y agoZig has bounds checking built-in. You can decide to remove it if you compile for ReleaseSafe instead of ReleaseFast, but it's always in debug builds.
- throwawaymaths 3y agoAlso note that you can compile your entire program in safety checked mode and compile functions with hot loops with release fast
- stefncb 3y agoI just realized I swapped the two but it's too late. The bounds checks obviously stay in ReleaseSafe, not ReleaseFast.
- wredue 3y agoSlices in zig are a fat pointer with a runtime known length, which have bounds checking at runtime and will panic if you access out of bounds. Unless you build in releasefast, which disables that check. There is releasesafe for a release build that keeps bounds checking panics.
- gcoakes 3y agoI think that's runtime safety protected. It should segfault if the program is built with "ReleaseSafe", the variable value is only known at runtime, and the variable overruns the array. There's a "ReleaseFast" mode which disables things like this. Also, if that variable is somehow known at comptime, then I'm pretty sure it will fail while compiling which is what you would want.
- llimllib 3y ago> If I were to use indices out of range, presumably that would that give me a compile time error? yup $ zig test test.zig test.zig:8:56: error: index 3 outside array of length 2 std.debug.print("\ncompile error: {d}\n", .{slice2[3]}); > Could I use variables as the indices and, if so, could I get a seg fault at runtime or are there some sort of guards on there? Bounds are checked by default: $ zig test test.zig test.zig:9:56: error: index 3 outside array of length 2 std.debug.print("\ncompile error: {d}\n", .{slice2[invalid_index]}); But you can disable them by building in `ReleaseFast` mode[1] Here's a test file you can use to play around with it if you like: const std = @import("std"); test "bounds" { var arr = [_]u32{ 1, 2, 3, 4, 5, 6 }; // 1, 2, 3, 4, 5, 6 const slice1 = arr[1..5]; // 2, 3, 4, 5 const slice2 = slice1[1..3]; // 3, 4 const invalid_index: usize = 3; std.debug.print("\nslice2: {d} {d}\n", .{ slice2[0], slice2[1] }); std.debug.print("\ncompile error: {d}\n", .{slice2[invalid_index]}); try std.testing.expect(slice2.len == 2); } 1: https://ziglang.org/documentation/master/#Build-Mode https://ziglang.org/documentation/master/#Build-Mode