Live data from Hacker News

Problems of C, and how Zig addresses them

avestura.dev

21–30 of 290 posts

Re: Problems of C, and how Zig addresses them

#21
post #9

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 th…

I 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.

Re: Problems of C, and how Zig addresses them

#22
post #6

Naturally it doesn't show how it tackles use-after-free cases.

Yup. It offers tests as a solution, which is nice I guess, but kind if reminds me of Valgrind.

Another thing that caught me by surprise is passing arrays as references. Ages ago we used to pass arrays (`int arr[100]`) as pointers (`int*`). I'm sure C still supports this?

Re: Problems of C, and how Zig addresses them

#23
post #6

Naturally it doesn't show how it tackles use-after-free cases.

Yup. It offers tests as a solution, which is nice I guess, but kind if reminds me of Valgrind. Another thing that caught me by surprise is passing arrays as references. Ages ago we used to pass arrays (`int arr[100]`) as pointers (`int*`). I'm sure C still supports this?

Just wondering - how well does Valgrind work on Zig projects?

Re: Problems of C, and how Zig addresses them

#24

Earlier quoted context omitted.

Would you mind elaborating on the complications you ran into? I ask because I think you used std.HashMap instead of std.AutoHashMap, the latter of which automatically chooses a hash function based on the types provided.

It was a little over a week ago now so my memory is a bit hazy, but I'll try to the best of my knowledge. Without getting into the weeds of why (happy to do so, just want to keep this readable), basically I needed to define and populate a hashmap in a new script and then import it into my main script, which to my mind left me with two options: * Define and initialise it at the same time (my preferred method) as a con…

I think for the first point you wanted a block that evaluated to the map, unsure if that’s what you wanted though

Re: Problems of C, and how Zig addresses them

#25
post #17
post #9

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 th…

Zig 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.

Also note that you can compile your entire program in safety checked mode and compile functions with hot loops with release fast

Re: Problems of C, and how Zig addresses them

#28

I'm no expert on either languages, but I tried Zig for the first time properly the other day. I really liked it up until I hit hashmaps. One thing that I think goes under-appreciated about C (and other languages with a similar paradigm) is thats its pretty upfront and clear about what it can and can't do out of the box. If you want hashmaps in C, you need to create your own implementation, otherwise think of a way ro…

As counter point, the way that Zig implements hash maps is absolutely instrumental for TigerBeetle.

Zig hashmaps _are_ quite a bit more cumbersome than, eg, in Rust --- you need to decided whether you want the allocator to be bundled with the hasmap, and its also up to the user of the hash map to provide equality and hash code (and, of course, there's manual defer instead of RAII).

However, this flexibility and verbosity comes with a super-power --- you can pass an allocator to a hash map at creation time, and then _not_ pass an allocator when you actually use the hash map. This is huge. This means that we get compile-time guarantee that we follow rule 3 of NASA's 10 rules

    3. Do not use dynamic memory allocation after initialization.
And we _still_ can enjoy using a hashmap from the standard library! No other language I know has an equivalent tool.

Re: Problems of C, and how Zig addresses them

#29
post #6

Naturally it doesn't show how it tackles use-after-free cases.

Rather than offer drive-by criticism, perhaps you could illustrate 'the problem' you are suggesting is being hidden?

The problem I believe is being discussed is that dereferencing a pointer after the memory it references is freed does not throw a warning at compile time. This means the programmer has to manually keep track of pointers, making sure not to free the relevant memory until there are no more references to it lingering about. While there are programming techniques which to lesser or greater extent prevent problems from occurring, e.g. by allocating all memory needed at the begin of the program and freeing all of it at the end, doing no (de-)allocation while the program is running; such solutions still require some discipline on part of the programmer and for some it is a tall ask.

Re: Problems of C, and how Zig addresses them

#30
post #9

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 th…

> 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
Post reply on HN