Live data from Hacker News

Problems of C, and how Zig addresses them

avestura.dev

41–50 of 290 posts

Re: Problems of C, and how Zig addresses them

#41
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? 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 bui…

Why not just compile your whole program safe and then demarcate which functions you want to not be safety checked?

Re: Problems of C, and how Zig addresses them

#42

You can repeat "C is a minimal abstraction over assembly" as many times as you want, it doesn't make it true.

It's true and false at the same time. The operations C gives you map 1-to-1 with assembly. Given some C code you can quite accurately predict which loads/stores will be elided by the compiler and what the resulting assembly will be. I can't name another language for which this is true. I get that you're hinting at the insane level of undefined behaviour enforcement by compilers, but I don't think it matters all that…

> It's true and false at the same time. The operations C gives you map 1-to-1 with assembly. Given some C code you can quite accurately predict which loads/stores will be elided by the compiler and what the resulting assembly will be.

I mean, can you though? After all you won't even have the same output depending on compiler and flags. And of course not all architectures have the same capabilities, so the same code can compile to a various number of instructions depending on the target architecture.

Not to mention things like bitfield access that can result in non-atomic load/stores for a simple `foo->bar = 1;`

I'm not sure in what sense you could say that C operations map 1-to-1 with assembly any more than Rust, C++ or basically any compiled language.

Re: Problems of C, and how Zig addresses them

#43
It is nice and innovative, no doubt. But reinventing the syntax from scratch instead of introducing just the minimal amount of changes to the original C is a barrier that will deter 90% of possible adopters.

The reason C# took off is that it's as close to C/C++ as possible. If there is a difference, it's due to a fundamental semantic change. E.g. it moved from painstakingly reinterpreting hundreds of small header files for each compiled source file to loading efficiently serialized hierarchies of class definitions. Hence #include got replaced with using. It changed the semantics of pointers vs. references, hence 'ref' instead of '*', and so on. But there is no "fn square(x: u32)" instead of "uint32_t square(uint32_t x)" just for the sake of it.

And that's the main reason why many people will never consider even looking into the advantages Zig offers. Keeping another syntax in your head is just not worth it.

Re: Problems of C, and how Zig addresses them

#44

Earlier quoted context omitted.

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?

Exceptionally well. Zig by default outputs valgrind client requests to annotate undefined memory. This makes Valgrind even more an effective tool for zig code than for C code.

Re: Problems of C, and how Zig addresses them

#45

You can repeat "C is a minimal abstraction over assembly" as many times as you want, it doesn't make it true.

It's true and false at the same time. The operations C gives you map 1-to-1 with assembly. Given some C code you can quite accurately predict which loads/stores will be elided by the compiler and what the resulting assembly will be. I can't name another language for which this is true. I get that you're hinting at the insane level of undefined behaviour enforcement by compilers, but I don't think it matters all that…

> The operations C gives you map 1-to-1 with assembly

    int test(int x, int y) {
        return x % y;
    }

    test:                                   // @test
        sdiv    w8, w0, w1
        msub    w0, w8, w1, w0
        ret
Surprisingly, assembly doesn't have the remainder instruction, but instead it has a multiply-then-subtract instruction which is not corresponding 1-to-1 to anything in C.

Re: Problems of C, and how Zig addresses them

#46

Tangentially... I'm grateful that these new batches of systems languages have chosen to use the u8, i32, etc, style integer types. Rather than the uint8_t and int32_t style. First thing I do in any of my low level embedded C projects is put in the various uNN/iNN types.

do you mean just to save the _t and int substrings, over and over? (if so, i agree)

Re: Problems of C, and how Zig addresses them

#47

It is nice and innovative, no doubt. But reinventing the syntax from scratch instead of introducing just the minimal amount of changes to the original C is a barrier that will deter 90% of possible adopters. The reason C# took off is that it's as close to C/C++ as possible. If there is a difference, it's due to a fundamental semantic change. E.g. it moved from painstakingly reinterpreting hundreds of small header fil…

Counterpoint: C itself invented lot of syntax compared to the contemporary ALGOLs and PL/I. Yet, it became immensely popular.

Re: Problems of C, and how Zig addresses them

#48

C is standardized and is one of the most (the most?) widely used programming language on the planet. If you write code targeting a C standard and don't include many unstable dependencies, it has a good chance of running correctly for a very long time. If you move from C to Zig, you lose that stability. Are Zig's convenience features really enough to compensate for this loss?

One of the main reasons, in fact, that we picked Zig for TigerBeetle (over C, which was the alternative, given we needed to handle memory allocation failure), was because of Zig's excellent interoperability with the C ABI.

For example, we write the reference TigerBeetle client implementation completely in Zig, then wrap this with the C ABI, and then bind to this C ABI from all target languages, to increase our velocity in how quickly we can ship language clients.

More details, in general, around our clients here: https://tigerbeetle.com/blog/2023-02-21-writing-high-perform...

Re: Problems of C, and how Zig addresses them

#49

You can repeat "C is a minimal abstraction over assembly" as many times as you want, it doesn't make it true.

It's true and false at the same time. The operations C gives you map 1-to-1 with assembly. Given some C code you can quite accurately predict which loads/stores will be elided by the compiler and what the resulting assembly will be. I can't name another language for which this is true. I get that you're hinting at the insane level of undefined behaviour enforcement by compilers, but I don't think it matters all that…

> The operations C gives you map 1-to-1

It does not. Implicit casting, inlining, volatile, args passed via registers vs stack etc can significantly change what you expect to be generated.

Re: Problems of C, and how Zig addresses them

#50
About macros and comptime: why is the compiler unable to detect that a function is a pure function, and if it is called with constants, the result can be computed ahead of time? At least in the simple cases such as the square example, which are I believe quite common, that would work. Maybe still add an annotation to make sure the compiler will do what the user expects, because humans are terrible compilers after all.

Because the "footgun" here is really that when using macros we are switching languages and strategies - in one case it's eager evaluation, and in the other is sort of like lazy evaluation.

Post reply on HN