Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Divide by zero must be undefined behavior in any performant language. On x86 you either have a if before running the divide (which of course in some cases the compiler can optimize out, but only if it can determine the value is not zero); or you the CPU will trap into the OS - different OSes handle this in different ways, but most not in a while that makes it possible to figure out where you were and thus do something about it. This just came up in the C++ std-proposals mailing list in the past couple weeks.

I mean look, I already agree that it's not necessarily unreasonable to have undefined behavior, but this statement is purely false. You absolutely can eat your cake and have it too. Here's how:

- Split the operation in two: safe, checked division, and fast, unchecked division.

- OR, Stronger typing; a "not-zero" type that represents a numeric type where you can guarantee the value isn't zero. If you can't eat the cost of runtime checks, you can unsafely cast to this.

I think the former is a good fit for C++.

C++ does not have to do what Rust does, but for sake of argument, let's talk about it. What Rust does here is simple, it just defines divide-by-zero to panic. How? Multiple ways:

- If it knows statically it will panic, that's a compilation error.

- If it knows statically it can not be zero, it generates unchecked division.

- If it does not know statically, it generates a branch. (Though it is free to implement this however it wants; could be done using CPU exceptions/traps if they wanted.)

What if you really do need "unsafe" division? Well, that is possible, with unchecked_div. Most people do not need unchecked_div. If you think you do but you haven't benchmarked yet, you do not. It doesn't get any simpler than that. This is especially the case if you're working on modern CPUs with massive pipelines and branch predictors; a lot of these checks wind up having a very close to zero cost.

> AFAIK all common CPUs have the same behavior on integer overflow (two-complement). However in almost all cases (again, some encryption code is an exception) that behavior is useless to real code and so if it happens your code has a bug either way. Thus we may as well let compilers optimize assuming it cannot happen as it if it does you have a bug no matter what we define it as. (C++ is used on CPUs that are not two-complement as well, but we could call this implementation defined or unspecified, but it doesn't change that you have a bug if you invoke it.)

It would be better to just do checked arithmetic by default; the compiler can often statically eliminate the checks, you can opt out of them if you need performance and know what you're doing, and the cost of checks is unlikely to be noticed on modern processors.

It doesn't matter that this usually isn't a problem. It only has to be a problem once to cause a serious CVE. (Spoiler alert: it has happened more than once.)

> For std::expected - new benchmarks are proving in the real world, and with optimized exception handlers that exceptions are faster in the real world than systems that use things like expected. Microbenchmarks that show exceptions are slower are easy to create, but real world exceptions that unwind more than a couple function calls show different results.

You can always use stack unwinding or exceptions if you want to; that's also present in Rust too, in the form of panic. The nice thing about something like std::expected is that it theoretically can bridge the gap between code that uses exceptions and code that doesn't: you can catch an exception and stuff it into the `e` of an std::expected value, or you can take the `e` value of an std::expected and throw it. In theory this should not have much higher cost than simply throwing.

> As for modules, support is finally here and early adopters are using it. The road was long, but it is finally proving it worked.

Last I was at Google, they seemed to have ruled out C++ modules because as-designed they are basically guaranteed to make compilation times worse.

For CMake, you can't really rely on C++ Modules. Firstly, the Makefile generator which is default on most platforms literally does not and as far as I know will not support C++ Modules. Secondly, it doesn't support header units or importing the STL as modules. For all intents and purposes, it would be difficult to even use this for anything.

For Bazel, there is no C++ Modules support to my knowledge.

While fact-checking myself, I found this handy website:

https://arewemodulesyet.org/tools/

...which shows CMake as supporting modules, green check mark, no notes! So that really makes me wonder what value you can place on the other green checkmarks.

> Long roads are a good thing. C++ has avoided a lot of bad designs by spending a lot of time thinking about problems about things for a long time. Details often matter and move fast languages tend to run into problems when something doesn't work as well as they want. I'm glad C++ standardization is slow - it already is a mess without add more half backed features to the language.

I'm glad you are happy with the C++ standardization process. I'm not. Not only do things take many years, they're also half-baked at the end of the process. You're right that C++ still winds up with a huge mess of half-baked features even with as slow as the development process is, and modules are a great example of that.

The true answer is that the C++ committee is a fucking mess. I won't sit here and try to make that argument; plenty of people have done a damningly good job at it better than I ever could. What I will say is that C faces a lot of similar problems to C++ and somehow still manages to make better progress anyways. The failure of the C++ standard committee could be told in many different ways. A good relatively recent example is the success of the #embed directive[1]. Of course, the reason why it was successful was because it was added to C instead of C++.

Why can't C++ do that? I dunno. Ask Bjarne and friends.

[1]: https://thephd.dev/finally-embed-in-c23



> What if you really do need "unsafe" division? Well, that is possible, with unchecked_div. Most people do not need unchecked_div. If you think you do but you haven't benchmarked yet, you do not. It doesn't get any simpler than that.

This attitude is why modern software is dogshit slow. People make this "if you haven't benchmarked, it doesn't matter" argument thousands of times and the result is that every program I run is slower than molasses in Siberia. I don't care about "safety" at the expense of performance.


> This attitude is why modern software is dogshit slow.

Bullshit. Here's my proof: We don't even do this. There's a ton of software that isn't safe from undefined behavior and it's still slow as shit.

> People make this "if you haven't benchmarked, it doesn't matter" argument thousands of times and the result is that every program I run is slower than molasses in Siberia. I don't care about "safety" at the expense of performance.

If you can't imagine a world where there's nuance between "we should occasionally eat 0.5-1ns on checking an unsafe division" and "We should ship an entire web browser with every text editor and chat app" the problem is with you. If you want your software to be fast, it has to be benchmarked, just like if you want it to be stable, it has to be tested. There's really no exceptions here, you can't just guess these things.


Modern software is dogshit slow because it's a pile of JS dependencies twenty layers deep.

Checked arithmetic is plenty fast. And as for safety vs performance, quickly computing the incorrect result is strictly less useful than slowly computing the correct one.


Google has a odd C++ style guide that rules out a lot of useful things for their own reasons.

There is no reason why make could not work with modules if someone wanted to go through the effort. The CMake people have even outlined what needs to be done. Ninja is so much nicer that you should switch anyway - I did more than 10 years ago.


I do use Ninja when I use CMake, but honestly that mostly comes down to the fact that the Makefiles generated by CMake are horrifically slow. I don't particularly love CMake, I only use it because the C++ ecosystem really has nothing better to offer. (And there's no chance I'm going to redistribute a project that can't build with the Makefile generator, at least unless and until Ninja is default.)

Anyway, the Google C++ style guide has nothing to do with why C++ modules aren't and won't be used at Google, it's because as-implemented modules are not an obvious win. They can theoretically improve performance, but they can and do also make some cases worse than before.

I don't think most organizations will adopt modules at this rate. I suspect the early adopters will wind up being the only adopters for this one.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: