Live data from Hacker News

The case against a C alternative

c3.handmade.network

341–350 of 388 posts

Re: The case against a C alternative

#341

The article misses a really big item. I’ve programmed in C for 20+ years and then recently switched to rust. When fellow C programmers ask me how Rust is going, I say “it’s modern” and “it’s consistent”. What I mean by that unlike C, Rust doesn’t have 50 years of baggage: string functions that handle null termination all differently, complicated implicit promotion rules, null-terminated strings that haven’t been a go…

When I discovered strsep was a thing I was genuinely a bit mad that I'd been "tricked" into using strtok all this time. Since then I never just look up a function in the standard library reference. It's a fair chance its API is far from ideal, especially in string.h

Re: The case against a C alternative

#342

Earlier quoted context omitted.

I haven't even suggested to roll your own "string" type. Not more than rolling any other type of array or slice. In my programs I normally do not define a "string" type. Not a central one at least. Zero-terminated strings work just fine for the quick printf() or fopen(). Instead, I might have many string-ish types. A type to hold strings in the UI (may include layout information!), a type of string slice that points…

Any length delineated string you're using, and you did say you were using length delineation, suffers from the problem of not being compatible with any other C code. There's a good reason operating system API calls tend to use 0 terminated strings. If you want to do a quick debug printf() on it, well, you could use %.*s, but it's awkward and ugly (I speak from lots of experience). Otherwise, you gotta append the zero…

Sure, I know who you are but I hold opinions too :-)

I don't care about having to provide zero-terminated strings to OS and POSIX APIs, because somehow I almost always have the zero already. Maybe I'm a magician.

Sometimes I have not, but >99% of what I give to printf is actually "text", and that pretty much always has the zero anyway. It's a C convention, you might not like it, but I don't sweat it.

If I want to "print", or rather "write", something other than a zero-terminated string, which is normally "binary data", I use... fwrite() or something analogous.

> C ranks among the most inconvenient string processing languages

I've written my share of parser and interpreters (including also a dysfunctional toy compiler with x64 assembler backend, but doesn't matter here), so I'm not entirely a stranger to this game either.

I find parsing strings in C is extremely _easy_, and I find it in fact easier than say in Python where going through a stream of characters one-by-one feels surprisingly unpythonic.

Writing a robust, human-friendly parser with good error reporting and some nice recovery attributes is on the harder side, but that has nothing to do with C strings. A string input for the average parser isn't even required, you just read char by char, frankly I don't understand what you're doing that is hard about it. It doesn't matter one bit if there's a zero at the end or not.

Re: The case against a C alternative

#343
post #228

Earlier quoted context omitted.

Not to mention that both C++ and Rust can specialise algorithms and containers for specific types, whereas in C most developers resort to void* and function pointers. It's not unusual to see C programs written in a "typical" C style become dramatically faster when rewritten in a more modern language. For example, typical C programs also don't use hashtables even when this makes the most sense, causing weird performan…

It's not unusual to see C programs written in a "typical" C style become dramatically faster when rewritten in a more modern language. This was equally true back when C vs Fortran was the big debate, and something not easily captured in benchmarks. C, as written by an expert in high performance C, was equally fast as Fortran written by an expert in high performance Fortran. C, as written by a domain expert with limit…

This actually reminds me a bit of an old competition between two Microsoft MVPs comparing C++ and C#, where they went back and forth optimizing their respective versions of a model program, and discussing the optimizations they made.

The gist, as I recall it was: the initial, idiomatic, written-for-maintainability version of the C# program was significantly faster than the C++ equivalent. Up until the end, the C# version also generally needed to go through less heroics to keep up with the C++ version. Eventually, the final C++ version did end up being faster than the fastest C# one, but, considering what needed to be done to get there, it was a decidedly Pyrrhic victory.

One huge mitigating factor, though, is that the model program was doing something business-y. I doubt C++ would have had such a hard time of it if it had been a number crunching or systems program.

Re: The case against a C alternative

#344

I just want: C with: - bounds checking - use after free checks - modules - sane metaprograming/template - tagged union built in without: - macro - pre declaration - split header/source That's it, no borrow checker, no weird syntax, no nothing So far D is the answser for me, but i'm worried about its future, will they keep improve the language in that direction? or will they continue with their high level stuff Zig/Ja…

Have you looked at C3 (the language OP is making)? I think it hits a lot of your boxes.

I looked at it; and i'm not really a fan of the syntax, `fn` feels out of place

Also no language server is a hard pass, tooling is important

Re: The case against a C alternative

#345
post #129
post #72

Earlier quoted context omitted.

First, not all language safety features have to manifest themselves as run-time checks. A properly designed language will allow many safety checks to be done at compile-time. And second, would you really rather deal with security holes on an on-going basis? The problem with C is not that you can write unsafe code in it, it is that the design of the language -- and pointer aliasing in particular -- makes it impossible…

I'm not here to defend C, but to point out a problem that many advocates make when they cherry pick examples of how their language is both safer and more performant than C. Simply put, that example is irrelevant when the size of the array is not known at compile time. The moment that you have a dynamically allocated array, you are either dropping safety (e.g. expecting the developer to perform bounds checks when nece…

There are patterns, though, that can help. C compilers are capable of recognising and optimising many forms of iteration, but being able to tell the compiler explicitly that you're iterating over a collection gives you that much more confidence that the compiler will do the right thing.

Especially when to get the compiler to do the right thing safely you need to add manual bounds checking with the expectation that the compiler will optimise it away, but without any mechanism to ensure that it actually happens.

It depends greatly on the problem at hand, but there are definitely cases where even with a dynamic array size we can unroll our loop such that we check bounds less than once per iteration.

Re: The case against a C alternative

#346

Earlier quoted context omitted.

Warning is one thing, but crashing is better. That's possible to do in a C compiler too of course, because in this example the array hasn't decayed to a pointer and its size can be recovered. The issue is when you pass the array to another function, it can't track the size without changing the ABI.

If the choice is between a compile time warning and a runtime crash, I will take the warning every single time: much closer to the actual error. You're probably asking for a compile time error instead. Indeed the `-Werror` option is often a good thing to have (though I don't set it by default on my free software projects, because other people might use other compilers with different warnings, and I don't want to bloc…

-Werror is an interesting case -- it's an example of a key difference between C and Rust.

Rust's compiler will reject programs unless it can prove them to be valid. C compilers will accept programs unless they can prove them to be invalid. But then C warnings can lead to an indeterminate state: code that looks iffy may be rejected, but we've not necessarily proven that the code is wrong. We're still trusting the programmers' claim that code which may exhibit undefined behaviour with certain inputs won't ever receive those inputs.

Re: The case against a C alternative

#347

Earlier quoted context omitted.

Warning is one thing, but crashing is better. That's possible to do in a C compiler too of course, because in this example the array hasn't decayed to a pointer and its size can be recovered. The issue is when you pass the array to another function, it can't track the size without changing the ABI.

If the choice is between a compile time warning and a runtime crash, I will take the warning every single time: much closer to the actual error. You're probably asking for a compile time error instead. Indeed the `-Werror` option is often a good thing to have (though I don't set it by default on my free software projects, because other people might use other compilers with different warnings, and I don't want to bloc…

I meant a crash. Obviously both at once is best, but you can detect the possibility of the crash at compile time (disassemble your program and see the bounds check), and it turns a possible security issue into a predictable crash so that’s safer.

I don’t really love forcing errors; when a program is “under construction” you should be able to act like it is and not have to clean up all the incomplete parts. It also annoys people testing new compilers against your code.

Re: The case against a C alternative

#348

Earlier quoted context omitted.

Any length delineated string you're using, and you did say you were using length delineation, suffers from the problem of not being compatible with any other C code. There's a good reason operating system API calls tend to use 0 terminated strings. If you want to do a quick debug printf() on it, well, you could use %.*s, but it's awkward and ugly (I speak from lots of experience). Otherwise, you gotta append the zero…

Sure, I know who you are but I hold opinions too :-) I don't care about having to provide zero-terminated strings to OS and POSIX APIs, because somehow I almost always have the zero already. Maybe I'm a magician. Sometimes I have not, but >99% of what I give to printf is actually "text", and that pretty much always has the zero anyway. It's a C convention, you might not like it, but I don't sweat it. If I want to "pr…

The inconvenience and inefficiency is apparent when building functions to do things like break up a path & filename & extension into components and reassemble them. You wind up, for each function, dealing with 0 termination or length, separately allocated or not, tracking who owns the memory, etc. There's just no satisfying set of choices. Maybe you've found an elegant solution that never does a defensive copy, never leaks memory, etc., but I never have, and I've never seen anyone else manage it, either.

Re: The case against a C alternative

#349

Earlier quoted context omitted.

Exactly! And because you can't create a substring without mutating the original value, you see that C code often needs to resort to unnecessary copying as well.

No. You can't create a zero-terminated substring other than a proper suffix or a buffer copy. But that's not really a surprise right? Well then, don't use zero-terminated strings for proper string processing. You don't have to use zero-termination, even when some programmers in the 70s and 80s were convinced enough of it that abominations like strtok() landed in the standard.

>You don't have to use zero-termination

You can choose between zero-termination and having to convert strings back and forth when using idiomatic libraries.

Re: The case against a C alternative

#350

Earlier quoted context omitted.

Warning is one thing, but crashing is better. That's possible to do in a C compiler too of course, because in this example the array hasn't decayed to a pointer and its size can be recovered. The issue is when you pass the array to another function, it can't track the size without changing the ABI.

If the choice is between a compile time warning and a runtime crash, I will take the warning every single time: much closer to the actual error. You're probably asking for a compile time error instead. Indeed the `-Werror` option is often a good thing to have (though I don't set it by default on my free software projects, because other people might use other compilers with different warnings, and I don't want to bloc…

> Indeed the `-Werror` option is often a good thing to have (though I don't set it by default on my free software projects, because other people might use other compilers with different warnings, and I don't want to block them outright).

Another problem with C. There's way too much implementation-dependent behavior.

Post reply on HN