Live data from Hacker News

In Defense of C++

dayvster.com

441–450 of 470 posts

Re: In Defense of C++

#441
post #434

Earlier quoted context omitted.

> Start by not calling everybody disagreeing with you a cultist, next time. You'd do very well as a culture war pundit. Clearly I wasn't describing a particular kind of person, no, I'm clearly I'm just talking about everyone I disagree with /s

So, not interested at all in how to deal with dependencies without git submodules, I reckon? We can stop here indeed.

You misunderstand, I am already well aware. My comment about your lack of elaboration was not due to any ignorance on my part, but rather to point out how you assumed that and refused to elaborate anyway. The idea that I may have my reasons for preferring dependencies-as-git-submodules or their equivalents (like Zig's package system) never crossed your mind. Can't say I'm surprised. Oh well.

Re: In Defense of C++

#442
post #434

Earlier quoted context omitted.

So, not interested at all in how to deal with dependencies without git submodules, I reckon? We can stop here indeed.

You misunderstand, I am already well aware. My comment about your lack of elaboration was not due to any ignorance on my part, but rather to point out how you assumed that and refused to elaborate anyway. The idea that I may have my reasons for preferring dependencies-as-git-submodules or their equivalents (like Zig's package system) never crossed your mind. Can't say I'm surprised. Oh well.

> The idea that I may have my reasons for preferring dependencies-as-git-submodules

Well, git submodules are strictly inferior and you know it: you even complained about the fact that it is a pain when some dependencies use different build systems.

You choose a solution that does not work, and then you blame the tools.

Re: In Defense of C++

#443
post #442

Earlier quoted context omitted.

You misunderstand, I am already well aware. My comment about your lack of elaboration was not due to any ignorance on my part, but rather to point out how you assumed that and refused to elaborate anyway. The idea that I may have my reasons for preferring dependencies-as-git-submodules or their equivalents (like Zig's package system) never crossed your mind. Can't say I'm surprised. Oh well.

> The idea that I may have my reasons for preferring dependencies-as-git-submodules Well, git submodules are strictly inferior and you know it: you even complained about the fact that it is a pain when some dependencies use different build systems. You choose a solution that does not work, and then you blame the tools.

Okay, I'll bite: your proposed alternative to being able to specify exact versions of dependencies regardless of operating system or distro that I can statically include into a single binary, everything is project-local, guaranteed, is... what? Is it just "Don't"?

Re: In Defense of C++

#444

Earlier quoted context omitted.

> You have a team of 20 engineers on a project you want to maintain velocity on. With that many coooks, you have patches on top of patches of your build system ... The scenario you are describing does not make sense for the commonly accepted industry definition of "build system." It would make sense if, instead, the description was "application", "product", or "system." Many software engineers use and interpret the p…

I can only relate to you what I’ve observed. Engineers were hired to rewrite the Make-based system into Bazel and maintain it for single executable distributed to the edge. I’ve also observed this for embedded applications and other stuff. I’m not sure why you’re dismissing it as something else without knowing any of the details or presuming I don’t know what I’m talking about.

>>> You have a team of 20 engineers on a project you want to maintain velocity on. With that many coooks, you have patches on top of patches of your build system ...

>> The scenario you are describing does not make sense for the commonly accepted industry definition of "build system."

> I’m not sure why you’re dismissing it as something else without knowing any of the details or presuming I don’t know what I’m talking about.

My apologies for what I wrote giving the impression of being dismissive or implying an assessment of your knowledge. This was not my intent and instead was my expression of incredulity for a build definition requiring 20 engineers to maintain. Perhaps I misinterpreted the "cooks" responsible for build definition maintenance as being all of those 20 engineers. If so, I hope you can see how someone not involved in your project could reach this conclusion based on the quote above.

Still and all, if this[0] is the Bazel build tool you reference and its use is such that:

  With that many coooks[sic], you have patches on top of patches 
  of your build system where everyone does the bare minimum 
  to meet the near term task only and it devolves into a mess 
  no one wants to touch over enough time.
Then the questions I would ask of the project members/stakeholders are:

  1 - Does using Bazel reduce build definition
  maintenance verses other build tools such as
  Make/CMake/etc.?

  2 - Does the engineering team value reproducible build
  definitions as much as production and test source
  artifacts?

  3 - If not, why not?
EDIT:

To clarify the rationale behind questions #2 and #3:

Build definitions are production code, because if the system cannot be built, then it cannot be released.

Test suites are production code, because if tests fail, then the build should fail and the system cannot be released.

0 - https://bazel.build/start/cpp

Re: In Defense of C++

#445

Earlier quoted context omitted.

Overloaded operators were a terrible mistake in every programming language I've encountered them in. (Yes, sorry Haskell, you too!) I don't think move semantics are really that bad personally, and some languages move by default (isn't that Rust's whole thing?). What I don't like is the implicit ambiguous nature of "What does this line of code mean out of context" in C++. Good luck! I have hope for C++front/Cpp2. http…

Overloaded operators are great. But overloaded operators that do something entirely different than their intended purpose is bad. So a + operator that does an add in your custom numeric data type is good. But using << for output is bad.

Why is using << for output bad? From what I've seen, it's usually not too hard to figure out that the left hand side is some kind of stream and not a number.

Re: In Defense of C++

#446
post #439

Earlier quoted context omitted.

> operator Not that widely. You must be thinking of the IO streams part of the library. Yes, it's rather poor in many respects. But you don't have to use it! We have perfectly nice variadic printing functions these days! auto number = 42; std::println("Hello, {}! The answer is {}", "world", number);

std::println dates to C++23. This is very recent. You only have to be using Clang 18 (March 2024) or older to find the feature unsupported: https://godbolt.org/z/xPqYafhss (Clang 19 dates to September 2024, only a year ago.) In contrast, the standard C++ stream types have used operator<< overloading for more than 25 years. glog/gtest assertions continue to use it.

I said "these days"... C++ is an evolving language. And while it doesn't throw things away, it does collect enough "stuff" that you can choose to write nicer and more straightforward code than before.

Re: In Defense of C++

#447
post #442

Earlier quoted context omitted.

> The idea that I may have my reasons for preferring dependencies-as-git-submodules Well, git submodules are strictly inferior and you know it: you even complained about the fact that it is a pain when some dependencies use different build systems. You choose a solution that does not work, and then you blame the tools.

Okay, I'll bite: your proposed alternative to being able to specify exact versions of dependencies regardless of operating system or distro that I can statically include into a single binary, everything is project-local, guaranteed, is... what? Is it just "Don't"?

I'm not sure what you mean.

What I am saying is that using a dependency is formalised for build systems. Be it npm, cargo, gradle, meson, cmake, you name it.

In cargo, you add a line to a toml file that says "please fetch this dependency, install it somewhere you understand, and then use if from this somewhere". What is convenient here is that you as a user don't need to know about those steps (how to fetch, how to install, etc). You can use Rust without Cargo and do everything manually if you need to, it's just that cargo comes with the "package manager" part included.

In C/C++, the build systems don't come with the package manager included. It does not mean that there are no package managers. On the contrary, there are tons of them, and the user can choose the one they want to use. Be it the system package manager, a third-party package manager like conan or vcpkg, or doing it manually with a shell/python script. And I do mean the user, not the developer. And because the user may choose the package manager they want, the developer must not interfere otherwise it becomes a pain. Nesting dependencies into your project with git submodules is a way to interfere. As a user, I absolutely hate those projects that actually made extra work to make it hard for me to handle dependencies the way I need.

How do we do that with CMake? By using find_package and/or pkg-config. In your CMakeLists.txt, you should just say `find_package(OpenSSL REQUIRED)` (or whatever it is) and let CMake find it the standard way. If `find_package` doesn't work, you can write a find module (that e.g. uses pkg-config). A valid shortcut IMO is to use pkg-config directly in CMakeLists for very small projects, but find modules are cleaner and actually reusable. CMake will search in a bunch of locations on your system. So if you want to use the system OpenSSL, you're done here, it just works.

If you want to use a library that is not on the system, you still do `find_package(YourLibrary)`, but by default it won't find it (since it's not on the system). In that case, as a user, you configure the CMake project with `CMAKE_PREFIX_PATH`, saying "before you look on the system, please look into these paths I give you". So `cmake -DCMAKE_PREFIX_PATH=/path/where/you/installed/dependencies -Bbuild -S.`. And this will not only just work, but it means that your users can choose the package manager they want (again: system, third-party like conan/vcpkg, or manual)! It also means that your users can choose to use LibreSSL or BoringSSL instead of OpenSSL, because your CMakeLists does not hardcode any of that! Your CMakeLists just says "I depend on those libraries, and I need to find them in the paths that I use for the search".

Whatever you do that makes CMake behave like a package manager (and I include CMake features like the FetchContent stuff) is IMO a mistake, because it won't work with dependencies that don't use CMake, and it will screw (some of) your users eventually. I talk about CMake, but the same applies for other build systems in the C/C++ world.

People then tend to say "yeah I am smart, but my users are stupid and won't know how to install dependencies locally and point CMAKE_PREFIX_PATH to them". To which I answer that you can offer instructions to use a third-party package manager like conan or vcpkg, or even write helper scripts that fetch, build and install the dependencies. Just do not do that inside the CMakeLists, because it will most certainly make it painful for your users who know what they are doing.

Is it simpler than what cargo or npm do? No, definitely not. Is it more flexible, totally. But it is the way it is, and it fucking works. And whoever calls themselves a C/C++ developer and cannot understand how to use the system package manager, or a conan/vcpkg and set CMAKE_PREFIX_PATH need to learn it. I won't say it's incompetence, but it's like being a C++ developer and not understanding how to use a template. It's part of the tools you must learn to use.

People will spend half a day debugging a stupid mistake in their code, but somehow can't apprehend that dealing with a dependency is also part of the job. In C/C++, it's what I explained above. With npm, properly dealing with dependencies means checking the transitive dependencies and being aware of what is being pulled. The only difference is that C/C++ makes it hard to ignore it and lose control over your dependencies, whereas npm calls it a feature and people love it for that.

I don't deny that CMake is not perfect, the syntax is generally weird, and writing find module is annoying. But it is not an excuse to make a mess at every single step of the process. And people who complain about CMake usually write horrible CMakeLists and could benefit from learning how to do it properly. I don't love CMake, I just don't have to complain about it everywhere I can because I can make it work, and it's not that painful.

Re: In Defense of C++

#448

Earlier quoted context omitted.

Am I missing anything in the article about this problem in particular? Owning references are a part of modern C++, which should be covered by the author's arguments.

> Owning references are a part of modern C++ Maybe we're thinking of different things, but I don't think C++ has owning references, modern or not? There's regular references (&) which are definitely not owning, and owning pointers (unique_ptr and friends), but neither of those quite match Rust's &.

Ah, okay, that is a good point. I was not aware of that subtle difference, and replaced "owning reference" with "owning pointer" in my mind.

Re: In Defense of C++

#449

Earlier quoted context omitted.

Am I missing anything in the article about this problem in particular? Owning references are a part of modern C++, which should be covered by the author's arguments.

I think your parent may be slightly confused, in the sense of terminology: "owning reference" is a contradiction in Rust terms. Here's the document I believe your parent is referring to: https://docs.google.com/document/d/e/2PACX-1vSt2VB1zQAJ6JDMa... The claim in the article: > Yes, C++ can be made safer; in fact, it can even be made memory safe. The claim from this document: > We attempted to represent ownership and…

Thanks for the clarification!

However, I also got confused, and just subsituted "pointer" for "reference" in my head. References, apart from smart pointers, are indeed a problem for memory safety.

Re: In Defense of C++

#450
post #447

Earlier quoted context omitted.

Okay, I'll bite: your proposed alternative to being able to specify exact versions of dependencies regardless of operating system or distro that I can statically include into a single binary, everything is project-local, guaranteed, is... what? Is it just "Don't"?

I'm not sure what you mean. What I am saying is that using a dependency is formalised for build systems. Be it npm, cargo, gradle, meson, cmake, you name it. In cargo, you add a line to a toml file that says "please fetch this dependency, install it somewhere you understand, and then use if from this somewhere". What is convenient here is that you as a user don't need to know about those steps (how to fetch, how to i…

While I do appreciate you taking the time to write that, I am somewhat at a loss. How does this justify the antipathy towards notions of a first-party build system and package manager? That's how we got into this argument with each other: I was calling out C/C++ cultists who cling to the ugly patchwork of hacky tooling that is C/C++'s so-called build systems and decry any notion of a first-party build system (or even a package manager to boot) as being destined to become just like npm.

C/C++ developers clearly want a build system and package manager, hence all this fragmentation, but I can't for the life of me understand why that fragmentation is preferable. For all the concern about supply-chain attacks on npm, why is it preferable that people trust random third-party package managers and their random third-party repackages of libraries (eg: SQLite on conan and vcpkg)? And why is global installation preferable? Have we learnt nothing? There's a reason why Python has venv now; why Maven and Gradle have wrappers; etc. Projects being able to build themselves to a specification without requiring the host machine to reconfigure itself to suit the needs of this one project, is a bonus, not a drawback. Devcontainers should not need to be a thing.

If anything, this just reads like Sunk Cost Fallacy: that "it just works" therefore we needn't be too critical, and anyone who is or who calls for change just needs to git gud. It reminds me of the never-ending war over memory safety: use third-party tools if you must but otherwise just git gud. It's this kind of mindset that has people believing that C/C++'s so-called build systems are just adhering to "there should be some artificial friction when using dependencies to discourage over-use of dependencies", instead of being a Jenga tower of random tools with nothing but gravity holding it all together.

If it were up to me, C/C++ would get a more fleshed-out version of Zig's build system and package manager, ie, something unified, simple, with no central repository, project-local, exact, and explicit. You want SQLite? Just refer to SQLite git repository at a specific commit and the build system will sort it out for you. Granted, it doesn't have an official build.zig so you'll need to write your own, or trust a premade one... but that would also be true if you installed SQLite through conan of vcpkg.

Post reply on HN