Live data from Hacker News

Matt Godbolt sold me on Rust by showing me C++

collabora.com

511–520 of 675 posts

Re: Matt Godbolt sold me on Rust by showing me C++

#511
post #464

All this has been known in the PL design community for decades if not half a century by now. Two things are incredibly frustrating when it comes to safety in software engineering: 1. The arrogance that "practitioners" have against "theorists" (everyone with a PhD in programming languages) 2. The slowness of the adoption of well-tested and thoroughly researched language concepts (think of Haskell type classes, aka, Ru…

If the practitioners haven’t adopted what you’re offering for 50+ years, that thing can’t be good. Rust is also struggling with its “too theoretical” concepts by the way. The attempts of the community to gaslight the practitioners that the concepts are in fact easy to learn and straightforward are only enjoying mild success, if I may call it that.

”If the practitioners haven’t adopted what you’re offering for 50+ years, that thing can’t be good.”

I don’t think what features are popular in C++ is good indication of anything. The language is good only due to the insane amounts of investment to the ecosystem, not because of the language features due to design.

For an industrial language inventory of ”nice features to have” F# and C# are mostly my personal gold standard.

”Too theoretical” is IMO not the correct lens to use. I would propose as a better lens a) which patterns you often use b) how to implement them in language design itself.

A case in point is the gang-of-four book. It mostly gives names to things in C++ that are language features in better languages.

Re: Matt Godbolt sold me on Rust by showing me C++

#512

Earlier quoted context omitted.

I meant panic if during any addition (including in runtime) an overflow occurs.

Why do you want a panic? Shift left. Overflow can be rejected at compile time for a price that you might be able to afford - generality. Just insist that the programmer prove that overflow can't occur, and reject programs where the programmer couldn't or wouldn't do this.

[deleted]

Re: Matt Godbolt sold me on Rust by showing me C++

#513

Earlier quoted context omitted.

The choice doesn't make sense because you want the program to always behave correctly and not only during development.

Eh, maybe. There's a performance tradeoff here and maintainers opted for performance. I'm sure many folks would agree with you that it was the wrong choice, and I'm sure many folks would disagree with you that it was the wrong choice. There are also specific methods for doing *erflow-checked arithmetic if you like.

Why should there be a performance tradeoff? Because Intel CPU doesn't have add-with-overflow-check instruction, we make our languages less safe?

Re: Matt Godbolt sold me on Rust by showing me C++

#514

Earlier quoted context omitted.

I meant panic if during any addition (including in runtime) an overflow occurs.

Why do you want a panic? Shift left. Overflow can be rejected at compile time for a price that you might be able to afford - generality. Just insist that the programmer prove that overflow can't occur, and reject programs where the programmer couldn't or wouldn't do this.

Programmer has other things to do. Computer or CPU should do the checks.

Re: Matt Godbolt sold me on Rust by showing me C++

#515
post #258

This reminds me of SQL's constraints, or pydantic's custom types and validators, which can validate that a value should be an int, and between 0-999, and not exceed, e.g. -1 or 1000. pydantic is a library for python, but I'm not aware of anything similar in rust or golang that can do this yet? (i.e. not just schema validation, but value range validation too)

The semantics are a little different in that you have to explicitly call .validate(), but Rust's "validator" crate[0] feels a lot like Pydantic to me.

[0]https://docs.rs/validator/latest/validator/

Re: Matt Godbolt sold me on Rust by showing me C++

#516
post #506

Earlier quoted context omitted.

A lot UB is things you wouldn't do anyway. While it is possible to define divide by zero or integer overflow, what does it mean. If you code does either of those things you have a bug in your code (a few encryption algorithms depend on specific overflow behavior - if your language promises that same behavior it is useful). Since CPUs handle such things differently whatever you define to happen means that the compiler…

This is a bad answer too, IMO. I think there is a solid case for the existence of undefined behavior; even Rust has it, it's nothing absurd in concept, and you do describe some reasoning for why it should probably exist. However, and here's the real kicker, it really does not need to exist for this case . The real reason it exists for this case is due to increasingly glaring deficiencies in the C++ language, namely,…

I cannot follow your rant... I'll do my best to respond, but I'm probably not understanding something.

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.

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.)

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.

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

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.

Re: Matt Godbolt sold me on Rust by showing me C++

#517
post #269

> Before we go any further, let me just say he acknowledges floating point is not right for price and later talks about how he usually deals with it. But it makes for a nice example, bear with us. OK but "this makes for a nice example" is silly, given that the only reason the example throws an error is that you used a float here, when both `quantity` and `price` would have been ints. error[E0308]: arguments to this f…

Why are they "ints" ? One of the first things we realise, in both C++ and Rust, is that we mostly don't want these primitives like "int", we want our own user defined types, and Rust is better at that in practice . In the C and C++ people tend to actually write the file descriptor will be an int, and the timeout will be an int, and the user account number will be an int, and the error code will be an int... because t…

Hah, it’s interesting - I program Rust mainly for resource constrained environments and everyone uses primitives. This was a good insight into how other people are thinking.

Re: Matt Godbolt sold me on Rust by showing me C++

#518

Earlier quoted context omitted.

> No, implicit conversion is a deliberate C++ feature and no analog existed in C No. > it's not a C choice, it's not about "compatibility". One of the design of C++ classes is that you can create a class as powerful as int - you can’t do that without implicit conversion.

It would have been perfectly possible - not to mention obviously better - to make people actually write what they meant when defining the new type and this has no impact on the dubious priority of being able to make your own int type by gifiting your type implicit conversions in use if that's what you want which it often is not. This is just another thing on the deep pile of wrong defaults in C++.

Yes, it’s a wrong default problem.

Re: Matt Godbolt sold me on Rust by showing me C++

#519
post #429
post #387

Earlier quoted context omitted.

It’s the sociology of software development. The guild of software developers has no real standards, no certification, no proven practices outside and while continuing to depend on the whims of project managers, POs and so-caled technical leaders and others which can’t tell quality code from their own ass. There’s usually no money in writing high-quality software and almost everything in a software development project…

Maybe. But I wouldn't diss better languages, linters, and other tool inprovements. These systematically increase quality at very low cost. It boggles my mind that the whole industry is not falling over itself to continuously embrace better tools and technology.

The whole industry is, the C++ ecosystem is just not.

Re: Matt Godbolt sold me on Rust by showing me C++

#520
post #506

Earlier quoted context omitted.

This is a bad answer too, IMO. I think there is a solid case for the existence of undefined behavior; even Rust has it, it's nothing absurd in concept, and you do describe some reasoning for why it should probably exist. However, and here's the real kicker, it really does not need to exist for this case . The real reason it exists for this case is due to increasingly glaring deficiencies in the C++ language, namely,…

I cannot follow your rant... I'll do my best to respond, but I'm probably not understanding something. 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…

> 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

Post reply on HN