| > You make some good, if oft-repeated, points They're oft repeated because they're real problems. > a plain Makefile works. > C has LSP support, like every other language. I haven't noticed C support in editors to be worse than other languages. Makefiles aren't supported well by clion or visual studio. LSP requires a compile-commands list to be able to work - which is a pita to export from makefiles. XCode and visual studio both require their own build systems. Etc etc. Its a mess. Even if you set up LSP properly, debugging can still be a PITA. Most of the time, it doesn't "just work" like in many other languages. In comparison, all Go projects look the same and all tooling understands them. Same for C#, Rust, Typescript, Zig, and many others. > 5. The modern idiocy of header files - this confuses me; there is still no good alternative to header files to support exporting to a common ABI. Other languages don't need header files, and yet they manage to export public interfaces just fine. Header files only exist because computers had tiny amounts of RAM in the 70s, and they couldn't keep everything in memory while compiling. The fact we keep them around in 2025 boggles my mind. Header files create 2 problems: 1. You have to write them and keep them up to date as your function signatures change, which is pure overhead. 2. They slow down compilation, because the compiler has to re-parse your headers for every codegen unit. Yes, PCH exists - but its platform specific and complicated to set up yourself. You can use unity builds instead, but thats fiddly and it can cause other headaches. > The downside of writing a product in C, in 2025, isn't in your list above. What would you say the downsides of writing a product in C in 2025 are? > One of my two main reasons for switching to C is because the product was so useful to paying clients that they'd like more functionality, which includes "use their language of choice to interact with the product." Yeah; I agree that this is one area where C shines. I really wish we had better ways to do FFI than C ABI compatibility everywhere. Rust, Swift, Zig, C++ and others can of course all compile to static libraries that look indistinguishable from C object files. But if you're using those languages, writing a C API is another step. If you're already working in C, I agree that its much easier to write these APIs and much easier to keep them up to date as your code changes. |
I dunno what IDE support I might need - once the Makefile is written I'm not going to be constantly adding and removing packages on a frequent basis.
As for IDE's, I am not using Clion, Visual Studio or XCode. Vim, Emacs and VSCode work fine with C projects, even when debugging interactively.
> What would you say the downsides of writing a product in C in 2025 are?
Slower initial development compared to HLL like Go, Python, etc. Well, it's slow if you want to avoid the major classes of bugs, anyway. You can go fast in C, but:
a) It's still not going to be as high-initial-velocity as (for example) Python, Java or C#
and
b) You're probably going to have a lot more bugs.
My standard approach to avoiding many of the pitfalls in using C (pitfalls which are also applicable to C++) is to use a convention that makes it easier to avoid most logic bugs (which, in the process avoids most memory bugs too). This convention does require a little more upfront design, but a lot more code.
So, yeah, I'll go slightly slower; this is not a significant enough factor to make anyone consider switching languages.
> Other languages don't need header files, and yet they manage to export public interfaces just fine.
Only for the isolated ecosystem of that language. C header files can be used to automatically perform the FFI for every single mainstream language.
So, sure, other languages can an export an interface to a file, but that interface probably can't be used for FFI, and in the rare cases where it can, it can't be automatically used.
C headers can, and are, used to automatically generated bindings for other languages.