4 ms·
> His dismissal of C++ as "not having a build system" seems like considering the language without the ecosystem. Using cmake and llvm solves all of his gripes o
by yakubin 6y ago
> His dismissal of C++ as "not having a build system" seems like considering the language without the ecosystem. Using cmake and llvm solves all of his gripes on C++.
Last week I debugged an issue in a big C++ codebase, where we were getting memory corruption. Source of the issue? Compiler, linker and build system being separate things and only compiler understanding types (also, lack of modules, which is another symptom of build system being separate from the language). Namely, conditional compilation was involved, someone made a struct which had a field in it based on whether a preprocessor constant was defined or not (passed with -D to the compiler on the command line). Turned out some files were compiled with the define and some not, so some files were compiled based on the assumption that this struct is N bytes long, and some with the assumption that this struct is N+M bytes long. But the linker doesn't have any information available to it to detect this error.
And then there is the issue that to write a C++ program these days, it doesn't suffice that you just know C++. Languages you need to know:
- C++
- language of your build system, which is always handicapped, yet Turing-complete
- Python
- if something goes wrong, and you need to debug something: Make with its custom shell-language
- shell
It's a tower of babel. For all the whining on users of other languages for using libraries, C++ users have a lot of complexity hidden in their build systems.
In Zig and the not-yet-released Jai, you only need to know the language you write your program in. The "if" in your language of choice is perfectly suitable for expressing conditional compilation. Structs in your language of choice are perfectly suitable for expressing declarative configuration.
- renox 6y agoYep been there done that two months ago, took me two days (at least) to find the issue as a corruption which happen in -O3 but not in debug build which neither valgrind nor ASAN can find is pretty mysterious..
- Too 6y agoUnless you left out some details, this sounds more like plain UB and buggy c++ code manifesting itself with different symptoms depending on the O level. This has not as much to do with the loosely coupled build system complexity you have to scaffold in a c++ project, more issues in the core language itself.
- renox 6y agoI won't go into detail but this was related to macros and separated compilations: if you're not careful with macros, the 'same' object can have different size in different .cpp..
- logicchains 6y ago>Namely, conditional compilation was involved, someone made a struct which had a field in it based on whether a preprocessor constant was defined or not No offense but this just sounds like bad design. Haskell has the C preprocessor so technically that particular criticism would apply to it too, but nobody would say it's Haskell's problem just because in theory people could use this feature to write terrible code. (I understand maybe this approach was necessary for interfacting with some other vendor/legacy code somewhere, but in that case the fundamental issue is still bad code, not C++: the bad vendor/legacy code).
- seoaeu 6y agoI've seen this sort of thing all the time. Not the part about different preprocessor defines in different files, but about having a struct's contents depend on some compile time conditions. It comes up when you want to track extra debug information but only for debug builds. It comes up if you need to store platform specific information in a common struct. It can come up if you have a major feature that you want to toggle on/off at compile time. Etc.
- yakubin 6y ago> Haskell has the C preprocessor I'm not sure what you mean by that. Are you saying you can use #ifdef, #include etc. in Haskell code? > No offense but this just sounds like bad design. I agree. However that's just one way you get multiple definitions for the same struct. I think a language should detect such an error. It will detect it for functions. If linkers did not detect multiple function definitions, would you shrug it off by saying "having multiple function definitions is bad design"? (I'm asking in a non-accusatory way. I'm not sure how to word the question more gently.) Many of us don't have the luxury of choosing the quality of code we're employed to debug. It would be nice if languages had some rudimentary sanity-checks to, well, preserve our sanity.
- logicchains 6y ago>I'm not sure what you mean by that. Are you saying you can use #ifdef, #include etc. in Haskell code? Yep: https://guide.aelve.com/haskell/cpp-vww0qd72 https://guide.aelve.com/haskell/cpp-vww0qd72. >Many of us don't have the luxury of choosing the quality of code we're employed to debug. It would be nice if languages had some rudimentary sanity-checks to, well, preserve our sanity. I agree, I don't think C++ is especially bad in this regard. If people are going to write bad code, they can write it just as well in Java, C#, Python etc., they'll just use different language features to bring about the horrors. No language (apart from maybe Go, in its extreme simplicity) can save us from having to debug bad code.
- megous 6y agoLinux kernel has a lot of these compile time optional struct members. I think they avoid this issue by using a config header file that contains the defines, so the compilation unit either compiles with the config header, or if it's not included and config macro is used, compilation fails altogether. It's still possible to include different config header than you're expecting, though. But that's easier to defend against. (you can just include a config header directly via cmd line without using #include <...> in each compilation unit) It's also better to use #if MACRO = 1 instead of #ifdef MACRO, because the first one will fail if MACRO is not defined.