The C++ Lifetime Profile: How It Plans to Make C++ Code Safer
pspdfkit.com
pspdfkit.com
In the first look Lifetime profile looks like it just tries to find the low hanging fruit cases.
Can it be further extended to guarantee safety guarantees in the future, or it's just a hack? I'm not sure about it.
I think Rust captures the core lifetime concepts pretty well, but the notation can be cumbersome, and I think C++'s rich type-system could make for a less-tedious solution. TFA mentions doing some implicit lifetime-analysis based on signatures (e.g. inferring ownership based on type-traits), but ultimately it is 'just' low-hanging fruit. It would be nice to capture in signatures/types that "the input must outlive the output" and have more meaningful error diagnostics and less implicit magic ("did I follow the iterator traits correctly?").
It's backwards compatibility: there are hundreds of millions, or probably billions of lines of C++ code out there. I found working with big code bases really hard, because the memory ownership situation is crazy, in fact impossible to keep track of.
That's why my question was whether there's a future path for C++ Lifetime Profile to get programs to Rust like memory safety in the future, but I still don't know the answer.
So any improvement to the status quo is pretty much welcomed, and here lies the big difference between the C++ (introducing lifetime profile) and C communities (making Annex K optional), regarding taking actions to fix memory corruption.
The C++ language maps one-to-one to the safe subset, so auto-conversion of (reasonable) existing C++ code to the safe subset should be a straightforward (if tedious) undertaking. The issue will be the performance of the converted code, which will depend on how pointers/references are used in the original code.
Pointers that are expected to never point to (in addition to never dereference to) a destroyed object can be converted to "safe" pointers with little run-time overhead [2]. Otherwise the pointer would need to converted to one with more overhead [3]. Pointers that can be verified (by the static analyzer) to conform to "scope lifetime" rules (akin to Rust) can remain zero-overhead pointers.
New code written in the safe subset would generally have performance in the ballpark of traditional C++ [4].
[1] https://github.com/duneroadrunner/scpptool
[2] https://github.com/duneroadrunner/SaferCPlusPlus#norad-point...
[3] https://github.com/duneroadrunner/SaferCPlusPlus#registered-...
[4] https://github.com/duneroadrunner/SaferCPlusPlus-BenchmarksG... (note that the benchmark code is quite old and will be updated soon)
Auto-conversion of code that uses pointer arithmetic is challenging, but has been demonstrated to be solvable in the general case [2].
[1] https://github.com/duneroadrunner/SaferCPlusPlus#getting-sta...
[2] https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla...
I hope it gets enough backing from corporations that have big/huge C++ code bases.
That's exactly right.
> Can it be further extended to guarantee safety guarantees in the future, or it's just a hack? I'm not sure about it.
It could be extended to catch more cases, but it can't realistically be extended to create a useful C++ dialect that is really memory safe. See https://robert.ocallahan.org/2018/09/more-realistic-goals-fo....
What the language needs is a new set of types that will ensure memory safety. Using the old types with the new ones should not allow the code to be compiled, thus ensuring memory safety.
It would be nice to have such a tool in short-term, though. At least some old bugs could possibly be more easily revealed.
I know, C++ is a dirty snowball rolling downhill, gobbling up every feature it can put its tendrils on, and always has been, but it is getting silly.
That's named evolving and improving. And that's how a language stay alive.
New code doesn't have to use old features.
Yeah but it's hard to manage in multiple ways. Is there good tooling to help? And it means a lot of references you could normally check are using features you can't use.
Plus none of your libraries are going to agree on what parts to use.
C++ has opted to avoid those struggles by never removing features; you can disagree with that decision but it was done for good reasons.
The register keyword issue crops up because legacy code included and linked to modern C++ will occasionally have the word "register" affixed to a loop variable. Generally speaking, once you change standards, there is room to drop the old stuff. It's just gradual. Static analyzers do a lot to modernize code now too, so the situation is not as painful as it used to be.
[0] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p188...
This statement does not do justice to the process that led to the renaming of "Perl 6" to "The Raku Programming Language". If you are interested in the process, https://github.com/Raku/problem-solving/issues/81 will give you some of the discussion that happened online.
gets(), exception specifications, semantic corrections for a couple of cases like decltype vs auto, auto original meaning, std::bind(), and several others
However they don't play a Python 3, and rather take the effort to minimize the impact of those changes.
But the interop story between modern cpp and older cpp is much better than the interop story between rust and older cpp.
On the other hand, Hell would freeze over before you could convince the business to throw the cpp codebase and replace it by anything else, without necessarily a lot of things to show to the customer. And as much as we like to criticize business decisions, here it is probably the right call.
However, if you are startup starting today, it would probably be a good idea to consider other options, that could be used as an advantage against incumbents.
Lots of code might not be updated, thing is, with C++20 I still get to compile my pre-C++98 code.
Even taking into account the breaking changes between language revisions, they are quite minor versus writing into another language.
Plus there are still lots of stuff missing, like a proper GUI library that can even compete with MFC, OWL, let alone something like UWP or Qt.
And that will be still be able to interop with the "everything else" that doesn't get updated.
(Perhaps not seemlessly, but certainly better than a Rust <-> C++ interop.)
For writing memory safe code I already have .NET and JVM set of programming languages, so when I need to go outside of these platforms, I rather pick the tool that provides zero attrition with the existing tooling.
These are all issues that will be fixed, but they aren't yet there.
C++ implementations have name mangling because they live on systems designed for C, which don’t allow symbols such as int max(int,int)
C implementations (would) need name mangling if they ran on a system that used case-insensitive comparisons on symbol names, or on ones whose character set is smaller than that allowed in C symbols (I know examples of neither, but Wikipedia has an example that encodes the calling convention in the symbol name: https://en.wikipedia.org/wiki/Name_mangling#C)
”If name mangling was standardized, could I link code compiled with compilers from different compiler vendors?
Short answer: Probably not.”
(click link for more info)
yet the real life answer is that I can link C++ code built with three different compiler on linux (gcc / clang / icc) and three / two on windows (clang / cl.exe / icc or clang / gcc)
That's not entirely true. C++ has a stable ABI: compiling a library with GCC and reusing it with clang or ICC is doable and commonly done nowadays.
The problem with the C++ ABI is that it is shamefully fragile. It is extremely easy to break an ABI without wanting it in C++, even for experts.
https://community.kde.org/Policies/Binary_Compatibility_Issu...
Neither the C Language Standard nor the C++ Language Standard specify an ABI.
Perhaps we should distinguish between a Langage-Standard ABI vs. a per-platform de facto ABI.
I think the GP's comment holds for the latter definition.
Even for C++: gcc has been mostly compatible, but not unreasonably so. MSVC was traditionally not at all, but has recently been for 2 or 3 major versions in a row. I think MSVC will eventually break it again though, but at least they break it way less often than before (and breaking can also have advantages).
Standard library implementations do not necessarily share the same ABI, but it is possible to interoperate between libc++ and libstdc++, and libstdc++ maintains ABI compatibility across different versions.
And, to be pedantic, C does not provide a stable, standard ABI. It is the platforms themselves that provide this ABI standard, and these platforms equally provide a C++ ABI standard. So C++ ABI compatibility is no more or less a problem than C ABI compatibility.
It's analogous to Java and Scala; each has an ABI, but it's easier to tell when the former breaks ABI than the latter.
There is a difference, but the difference is in complexity, not availability.