Survey results: ISO C++ feature proposals
herbsutter.com
herbsutter.com
I'm sick of the dumb preprocessor hacks required for something as simple as iterating through enum values with their string representations.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p070...
With this proposal, that's effectively impossible to do, without either being non-conforming ("with the additional restriction that any installed new_handler must terminate"), or not using any standard library code (which is proposed to not throw any exceptions: "For each standard function for which allocation is the only reportable error, make the function noex-cept").
It's practically impossible to use only explicitly checked allocations everywhere. One can do it for allocations that are more likely to fail (e.g. because they're large), but not for every small thing. In postgres, it's my experience that a very significant fraction of real-world allocation failures are on small allocations, not huge ones.
Now postgres is currently C (but that's imo more historical baggage than anything, and has pretty significant costs), but this would effectively prevent us from taking advantage of a lot of C++ if we ever decided to move.
FWIW, postgres OOM handling basically works by doing allocations via it's 'memory contexts', which check allocation failure (obviously only really possible if the OS signals them, requiring e.g. to explicitly change the overcommit settings on linux). Allocation failures are handled by switching to a memory context that sigsetjmp's to a higher level. That higher level then releases resources by bulk-releasing memory using the memory context mechanism, and handles other resources (locks, other resources) via the related resource owner mechanism. But that mechanism is - as far as I know - impossible to do in realistic confirming C++, because one cannot call all the relevant destructors.
You can have hidden allocations, you just need an exception mechanism. It sounds like Postgres does this with setjmp/longjmp. That's typical. I do that with my JSON C library--https://github.com/wahern/json/blob/master/src/json.h#L72 And setjmp/longjmp is how Lua implements its exceptions.
Lua is interesting in that it's a dynamically-typed scripting language that permits recovery from memory allocation failures in a rigorous manner. It doesn't add much if any complexity to the Lua implementation--if anything the discipline arguably helps keep things simpler. But it does require the Lua VM authors to always be mindful about maintaining consistency of the VM state. In particular it means they have to make sure all dynamically allocated memory is properly anchored in the object graph. This type of discipline isn't something you can refactor for after the fact, but it's not as difficult as it seems if you start out this way (modulo the lack of compiler enforcement). The Lua C API is also carefully designed--most routines are implemented and documented to not do any hidden allocations. And unlike any other scripting language with a C API I've used or examined, Lua provides a plethora of convenient abstractions for keeping foreign data pointers anchored in the object graph, as well as the mechanisms and semantics that permit both C and Lua code to catch and reliably recovery from exceptions, including allocation exceptions.
By contrast, while Go conceptually could provide OOM recovery--it has an exception mechanism almost identical to Lua's, and likewise uses non-copying GC--but much of the implementation makes the assumption that allocation never fails. As a practical matter correct, reliable, and consistent recovery from OOM isn't possible for Go. As I said, it's not the type of thing you can add after the fact. So instead you see a recapitulation of decades of myths[1] and contrivances[2] focused on "managing" memory. I only pick on Go because massive concurrency, and in particular massively concurrent network sessions, is it's niche. Even at "web scale" where you have the same Go process running on dozens or hundreds of other machines, this neglect to tackle allocation failure has resulted in often times exceptionally poor quality of service for Go apps. Without proper allocation failure recovery, "managing" memory becomes a black art rather than a science, with predictable results in terms of consistency and stability.
It's a shame to see C++ gleefully going down this road, seemingly having finally drunk the Kool-Aid and adopted the myth that handling allocation failure to too difficult and too error prone; that it's not your problem and something else higher up the stack will solve the problem for you. :(
[1] E.g. big allocations are more likely to fail
[2] E.g. reserving large blocks to be released according to some imaginative heuristic intended to predict and forestall allocation failure
I think the reasoning behind this part of the C++ proposal at hand is a bit more complicated than that. It's imo worth reading section 4.3 specifically about the memory allocation issue, and the motivation for the whole exception overhaul in in section 2 (although that's a bit longer).
The reasoning isn't itself that it's too difficult or such, it's that the overhead required by something like the current exception handling is high, and that it's quite desirable to makr a lot more of the standard library as not throwing exceptions - and the only cause a lot of them throw, is OOM.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p070...
How would a package management system for C++ work?
Would there be a centralized repository containing shared objects, static objects, and header files of all the packages? Who would pay for the hosting? How would you track which libraries are compatible with which compilers/OSes/architectures?
Seems like at this point it would be a herculean effort to create cpppm because of how fragmented the compilers/support is across systems. And so it would be a broken piece of garbage so people wouldn't use it.
Which build system? CMake? SCons? GNU Make? Unix Make? Autotools? Visual Studio Solution?
Cpp libraries are far from having a standardized build system. And without a standardized build system, you can't do what you describe.
I suppose you could say "CMake is the standard" and then only support CMake-compatible libraries, but again, that leaves hundreds of packages out of reach.
If there were some type of system where library A says it depends on library B (via a URL or some other non-centralized thing), and the compiler knows how to resolve this, then you don't need 90% of the features these tools provide. You still need build parallelization and maybe detection for non-standard compiler features, but this is a much smaller and simpler problem.
Because C/C++ compilers are fragmented. And because C/C++ is not very portable. If building for windows -> pass a bunch of -D flags to the compiler. If building for Linux, pass a different set of -D flags. Different compilers require different arguments.
> If there were some type of system where library A says it depends on library B ... and the compiler knows how to resolve this
Here's the crux of the problem. There is no organization that owns or maintains C++, unlike Rust. With Rust, there is only one compiler - rustc. With C++ there are at least 5 major ones maintained by 5 different (competing) organizations.
There's no way to do package management in C++ without massive build system rewrites. Consider:
I write a new C++ package called CoolCrypto. It depends on libssl. I wrote my package in CMake, libssl uses autotools. Barf, the package manager only speaks CMake and gives up.
Because depending on the use case you generally need to build the same software in a lot of different configurations : debug / release runtimes on windows, various sanitizers, static / dynamic / dynamic with LTO, you also want to build some files only on some platforms, you want your users to be able with / without tests / examples / implementations of various types (e.g. enable / disable network protocols or media codecs at build time for the two most common use cases I know), enable / disable profiling or coverage or tracing support... add a flag for having split debug info but you need to disable it if your users run ubuntu 16.04 because here it's broken, add a flag for linking with lld but you need to disable it on macos because it's broken, change debug mode to -Og if you're on a CI machine because -O0 takes too much space and you fill the Travis CI vm, except if you're on a worker with a recent enough toolchain to support -Wl,--compress-debug-sections=zlib
e.g. look at the configurability of something like ffmpeg : https://paste.ofcode.org/zBhsKWiSk3Gn73bkgfA9Yk
or qt : https://paste.ofcode.org/wmZZX9emiNr2uPksceZNz6
or one of the project I work on - most of the config flags here were added after the request of some users who wanted to be able to make a leaner build in some specific case ; making multiple shared libraries is a no-go first because then your users complain that they don't which of the five libraries they have to add to their system, and also because you loose LTO and have a lot of duplication of template instantiations (or monomorphized generics as it is said in Rust parlance): https://github.com/OSSIA/libossia/blob/master/cmake/OssiaOpt...
You rarely have complex problems with simple solutions.
> Would there be a centralized repository
> How would you track which libraries are compatible
> Seems like at this point it would be a herculean effort
This is not a bizarre or impossible idea.
Besides the plethora of package managers in more modern languages, there are in fact, actual real-world C/C++ package managers: Conan [1], Buckaroo [2], vcpkg [3], Conda [4], cget [5].
However, it's much like Go before its maintainers did anything: it's the Wild West and every day brings a new package manager.
Having some consensus, standardization, common concepts, or direction would help C++ adoption/usability enormously.
[3] https://docs.microsoft.com/en-us/cpp/build/vcpkg?view=vs-201...
As somebody who has used threads a lot and written code in kernel mode etc. something about this scratches me the wrong way.
The traditional concurrency toolkit has some issues. Being experienced with them can make you somewhat jaded against them. In particular, the standard way to solve problems in that mode of thinking is to introduce locks, and experienced people know all the problems that locks have, and that the "solution" is harmful in the extreme.
So it is acceptable for such a programmer to want more options, standardized. I would even argue that this is more important than introducing std::mutex, std::thread, or std::atomic, because you can say that in the pre-C++11 era nonportable interfaces like pthreads or win32 were already working OK for people that chose to use them.
nowadays I mostly see lock-free queues and message passing across threads, it's trivial to do with a few nice libraries
Compile-time programming is a very powerful feature of C++ that does not have an equivalent in other systems languages. It is commonly used to effect several types of compile-time verification of code design and safety that would be difficult to do any other way, in addition to its more obvious use case for effecting relatively complex performance optimization algorithmically. The ability to algorithmically generate almost arbitrarily complex types during compilation that are fit to purpose is an extremely useful feature for fast, high-reliability code and used pervasively in modern C++ as the facility has become more expressive. Filling some of the last remaining holes in its expressiveness would be high-value novel capability. Think of it as a hardcore safety feature.
You can put me in the camp that adding more support for concurrency in the language beyond a feature like coroutines (in C++20) and the existing primitives is not that useful. It would have the same issue as STL containers, where there simply isn't enough control of the implementation details for them to be used for many applications C++ is used for, so most concurrency infrastructure will be purpose-built anyway.
Pattern matching functionality can already be effected in many cases, albeit quite ugly. This would be more syntactic sugar than new capability, so I can understand why it isn't prioritized as much.
Yes, C++ compile time capabilities are powerful, but they aren't by all means the only game in town.
Some applications that are above the OS and device drivers, such as database engines, are clearly in the domain of systems applications because it is not possible to create a competent implementation without the control a systems language provides. Even for relatively abstract high-level software like distributed systems, strict control of scheduling is required for consistently robust throughput and behavior. Some key algorithms only work in real systems if resource management and concurrent operation sequencing is inexpensively deterministic. For some other applications, the only real benefit of a systems language would be for performance engineering purposes, which may not be a practical priority.
The "managed language" litmus test is quite good in my opinion, and almost definitional.
There's tons of reasons why this could be this way; and it shows why creating these kinds of things is just hard.
Another bias all voluntary surveys are prone to is prone to that's not listed is https://www.quora.com/What-is-voluntary-response-sampling-Wh...
So basically, don't use this data to make decisions :)
It's also a painful topic, considering how vastly outdated Qt's use of C++ is, and how many libraries are doing similar.
Poor 'Copper Spice'!
It’s a Frankenstein’s monster made of parts from other Frankenstein’s monsters. If Lovecraft were alive today this would be his prime eldritch deity. An abomination of impossible geometries you could not make sense of even if your eyes could see in 4D.
I'll start with a simple example. I haven't worked with C++ in ages and I hope never to, but in the last C++ file I came across:
Right at the beginning there were 3 different kinds of include/import statements.
One with "" and another with <> and I don't remember what the third was but it had yet another format.
Now, I know what they mean, or I can look it up, and there may be a valid need for the distinction, but it is ugly.
Here's another confusion I was recently reading about:
https://stackoverflow.com/questions/516237/when-should-i-use...
I find Assembly and "pure" C a lot more elegant than this nightmarish atrocity.
Specify specific paths by something like "$SYSTEM\foo.h" or "$CWD\foo.h"
Either would be more readable and less magic than <> or ""