C++17 – better than you might think
levelofindirection.com
levelofindirection.com
All the new stuff is heavily template based. As more libraries are written in that style, compile times go through the roof.
I wrote some code recently that required high precision monetary calculations. So I used boost multiprecision. It turned out to be completely impossible as most compilation units ended up depending on that library directly or indirectly.
Already slow compiles became unbearably slow. Facing a tight deadline I quickly wrote an extremely ugly, slow, error prone, pimpl based wrapper around boost multiprecision. Many calculations now require dynamic memory allocation for no good reason.
This is just terrible, because I know I can't leave it like this. I'm going to have redesign the whole thing or look for other libraries or look a lot more deeply into the calculations to see if they really cannot be done with large integers.
It's a productivity disaster. You could say I made wrong choices, which is true, but I think the C++ standards committee has been making wrong choices in not prioritizing a fix for compile times (modules?).
What's the point of having nice new features if you end up spending half your time on carefully cordoning off any code that uses them?
http://clang.llvm.org/docs/Modules.html#problems-with-the-cu...
For high precision currency, use int64_t (perhaps in a simple POD class). This, with an 8-digit implied decimal part, is enough to represent the finest price unit in any market today, with a max of 92 billion.
If you are dealing with more than 92 billion of any currency in a single place, don't complain!
Even in EUR/USD/GBP, a typical large bank balance sheet is over a trillon.
In my particular case, 64 bit integers might be sufficient. I thought about it but then decided I wanted to be on the safe side. Maybe not the best decision.
So I wanted perform the caculations with high precision, then round the final result according to what the law requires.
How so? If there's a resting offer at 11.58726 and I put in a buy order, limit 11.63492, there's no reason an exchange can't match that and execute either at the midpoint or at 11.58726 +/- maker/taker (whichever the exchange policy is). What's the problem?
My understanding is that all prices on exchanges have a fixed number of decimal (and sometimes are even based on less granular base, like 1/8th of a decimal).
There's an argument that more granular prices make it harder for humans to read the order book but I don't put much faith in it.
"Bank accounts with balances of up to 175 quadrillion Zimbabwean dollars will be paid $5. Those with balances above 175 quadrillion dollars will be paid at an exchange rate of $1 for 35 quadrillion Zimbabwean dollars.
"The highest – and last – banknote to be printed by the bank in 2008 was 100 trillion Zimbabwean dollars. It was not enough to ride a public bus to work for a week."
https://www.theguardian.com/world/2015/jun/12/zimbabwe-offer...
Gas stations in the US had a similar problem in the 1970s; most pumps didn't go over 99 cents a gallon. Took a few years for things to be retrofitted.
I'm sure no one dealing with zimbabwean currency would care for so many significant digits.
But you certainly could have a fast path for stable currencies that are very unlikely to hyperinflate (USD, EUR, GBP, JPY).
Having looked at the clang modules implementation you basically have to clean up all the system includes, the standard library and your own headers before you can use them. And you will have to rewrite many things in these headers due to changed preprocessor semantics.
I think neither the clang nor MSVC implementations can be used for anything but the most trivial code due to these issues.
There are talks from Google who invested heavily into modules using clang and got gains, but as far as I understand they fixed those issues only for themselves.
More info welcome.
At this point the only cure is brute force (blades with many cores are not that expensive, or a distributed compile cluster) and always taking care with your includes.
I am confident that by C++20 they will be available.
The main problem will be the adoption by major libraries.
Kernel headers are only an issue on free UNIX like OSes, on other OS what matters is what the SDK provides.
So at least in what concerns Apple, Google, Microsoft and every other commercial vendor OSes, don't expect a big issue having their SDKs updated when they start supporting modules.
The problem is getting the BSD, Linux and open source libraries without a specific agenda to adopt them.
Regarding the libc and other headers, modules will still fullly support include files, so that won't be an issue. You should be able to include headers and export them as modules.
libc and libstdc++ are part of the compiler runtime, ie. will be updated together with it.
I thought Google fixed the C++ compile time problem by inventing Go?
Go is hardly a replacement for C++. Garbage collection, no templates, no const, etc.
Aren't modules especially limited with the mentioned problem of templates? If I have a vector of a custom type, I still have to instantiate it in every file that is using this type, I don't think modules help much here, they reduce the amount of time parsing, not instantiating if I understand correctly.
We'll need to significantly change the way we handle templates in compilers to get significant improvement.
Past a certain point, long compile times make it harder to improve a large code base. People work around it by adding more stuff at the leaves and never fixing fundamental parts of the code base, avoiding to touch heavily shared code. This is almost a guarantee for another increase in compile time (because you end up accreting more stuff) which makes it even harder to work on the code base at large scale.
And that has I believe a concrete effect on the quality of a piece of software.
The problem is, there are some low hanging fruits (like caching, parallelizing and distributing builds) so people think they can delay the inevitable. The problem is, those counter measures only deal with the average case, while doing nothing about the worst case.
If you listen to the C++ advocates, they all say use the STL as much as possible, use boost if there is solution for your problem there, etc.. It's true, you probably will quickly get a solution that works and looks pretty, but if you do this a hundred or a thousand times your code suddenly needs several hours to compile.
I am not against the STL, or boost, but there is a cost associated with using them that is often ignored, but IMHO is actually a productivity killer in codebases that are a bit bigger.
Can you put numbers on these figures? By "Unbearably slow" how many minutes (or hours) did you mean? Do you use a heavy desktop with a fast SSD and a lot of RAM?
Finally what is the total output program size (roughly). Like are we talking about an application that is in the gigabytes, like the complete Adobe suite or something?
I would like to know more information about how it's possible for this to happen. tell us as much as possible :)
Thanks!
¹ I used it in a couple projects and never had a single incorrect build. With most other build tools, be it CMake or Gradle, these happen regularly for me.
"Unbearably slow" is when the compiler takes too long for me to stay focused on a single task. So compile times in the minutes are a blow to my productivity.
The machine is i7, 4 cores, 8G RAM, SSD. Definitely not as beefy as it should be.
But my point isn't about how to optimize C++ compile times by adding more hardware. It's about the relative impact of "modern" C++ compared to traditional C++. There shouldn't be a disincentive to using modern libraries.
Another thing is to rely on the preprocessor for code generation; then you're dealing with memory-speed elaboration of the AST, rather than reading off of disk.
In C and "older" C++, you're probably used to doing a particular style of separate compilation. You put your prototypes in header files, your implementations in cpp files, do the equivalent of `gcc -o somefile.o somefile.cpp` for every cpp file in your project. Each of those separate compilation stages has to include any referenced headers, but then it just compiles the code in that cpp file and writes an object file. At the end, you do one more step to link all the object files into a binary executable. This is fast and as parallelizable as the number of files you have.
In C++ today, you're likely doing a lot with templates, and templates don't work this way. With templates, every compilation unit that references a template needs not just declarations from a header file -- it needs the complete source code for that template. You essentially have to #include the cpp files (through one mechanism or another).
Simplifying a bit, that means that if you have a template defined in one file that is used by code in 25 other files, that template gets compiled 25 different times, and worse, you lose out on a lot of parallelism because by the time the compiler sees the code, the preprocessor has expanded the templates into one giant compilation unit that's going to be (slowly) compiled on one core.
I just grabbed the code I wrote during my PhD thesis that was heavily template-based. It's tiny (about 15,000 lines of C++) and building it on this $3000 2015 Macbook Pro took about a minute, and clang++ used a bit over 800 MB of memory in the process. (https://github.com/deong/sls if anyone cares to see the example).
You certainly don't have to be building the Adobe suite to see compile times in the tens of minutes, and even moderate sized applications can put you into the hours. So much just depends on how the application is structured and written as opposed to only looking at size.
Though I'm curious as to what you mean by "unbearably slow", and what your toolchain is.
I find the IDE to still be sufficiently fast after disabling some things like Git integration and codelens.
I found a really simple solution to this: disable all optimizations while you are developing and only use them for production build. I have 70k LOC project that compiles from scratch in 10-11 seconds (using 8 parallel builds).
Regular changes to 2-3 .cpp files and link are done in 1-2 seconds.
This is esp. important with MSVC which has a huge difference between non-optimized and optimized build.
Also, use precompiled headers.
I'm not paid to use them or shill for them I just think distributed compilation might help
While Boost often implements the latest proposed standards and provides a vast extension to the STL, it is not the STL. Often proposed standards changes are best implemented by changing the compiler itself. Expecting Boost to provide the same functionality as a modified compiler without a cost is foolish.
Boost provides great implementations but at a great cost in complexity, compile time and binary size bloat. I don't even really believe modules will solve this. They push the boundaries of what is possible with today's equipment, in order to discover what the next equipment should be.
Also I no longer look to Boost libraries as a Seal of Quality. There be dragons. Choose wisely.
what is unbearably slow ? an hour ? a day ? how many times did you actually have to rebuild the entire code base ? Did you do parallel builds, or see what gains you could get from faster hardware ?
I'm genuinely curious as I've never worked on a codebase that large, and the only time you have to rebuild everything is when someone changes a common library header.
In fact, a lot of modern software engineering guidelines come from working around C++'s built in shortcomings.
Use things such as the Pimpl idiom to help linking. Modular libraries rather than big-ball-of-mud, do you really need to recompile world+dog each time? Top-down includes, and no relative includes, isolating your code. In fact go-lang does exactly this.
The trouble is that in C++, fast compile times need to be designed into the code base and often enforced by scripts. I don't think that there's any other language that requires so much 'non-language' engineering as C++.
My pet peeve is Argument-Dependent Lookup. It's a hack that breaks the encapsulation of namespaces, increases compile times and still makes it harder to write code - try swap()ing two values of type T in a template function. But like any of C++'s warts, it will be with us forever.
Then you break backwards compatibility. What about static analysis to enforce a particular subset of features deemed idiomatic or otherwise best practice?
Granted, reducing complexity does make the job of future compiler authors far less miserable.
I like that idea.
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...
As a day-to-day C++ practitioner I like it.
...Yet I am not fully convinced that the general idea of language evolution implemented as ruleset outside of the language itself is the way to go. Seems more like band-aid to me and made me start to think about concept of programming language's life cycle in context of Darwinian evolution - once either legacy compatibility burden is too big or that particular biotope of specific problems the language solves better than others vanishes/changes the language dies out.
My particular issue with C++ is that it's complexity, longevity and evolution made possible for widespread bad-practices as not every C++ developer evolved as much as the language itself and it's general public understanding. (Some current best-practices were simply not always widely known or accepted.) I would even go as far to say that most of existing C++ code is crap (at least from standpoint of today "modern" C++).
And that's why I am both eagerly looking to "next generation" being shaped up by people who has (hopefully) learnt from past mistakes and used by people who care (itching to give Rust a ride once it stabilizes just a bit more) and also occasionally digging in the history for possible gems that I might not able to see without my current experience (platonic weekends-only relationship with Haskell, Lisp being right there at top of my TODO list).
EDIT: Removed the sir.
You may want to take a quick gander at the profile of whom you're replying to. :)
>... itching to give Rust a ride once it stabilizes just a bit more ...
Likewise, though from my limited research it seems Rust has legacy baggage of its own already, and there's difficulty in coming to a consensus on what qualifies as idiomatic Rust. It seems that the same principle of cherry-picking a subset of features would apply just the same to Rust as it does to C++. The latter being far messier, of course.
What is considered legacy cruft in Rust? The only change I'm aware of was the introduction of the `?` operator to replace the `try!` macro. That's easy to find/replace.
Some of these aren't examples of legacy cruft per se. However, as complexity is added to a language at a rapid rate, there becomes more confusion over what best practice actually is.
[0] https://www.reddit.com/r/rust/comments/2r7ttq/where_to_find_...
[1] https://users.rust-lang.org/t/rust-version-support-in-librar...
[2] https://gist.github.com/lifthrasiir/cedb5db8dbcd209c5957
[3] https://users.rust-lang.org/t/is-this-idiomatic-rust/2155
What most people nowadays recommend programming in is actually not C++, and actually C++ + all compiler warnings, which is in itself an extension/evolution/restriction of the underlying language. So it's not so far out to go from there to externalizing more rules around valid programs.
There's every reason to think that evolving human systems should use similar masks on features of a technology to make it more suitable for a particular domain and serve as a signal to drive the base evolution.
The restricted C subset used for safety critical systems I think is a good example of this -- the restriction allows for usage in a domain where the full set of features is a disadvantage.
I think you are right - as far as 'the' language is concerned. The complexity (and the slowness) of a C++ compiler now is mostly due to the complexity - and the slowness - of the built-in interpreter of the template meta-language. There are other, saner languages, such as Common Lisp, where the meta-language is indistinguishable from the language itself, which, in addition to its greater simplicity, greatly contributes to the reasonable compile times. In the C/C++ land, it might have been possible to use a similar approach instead of introducing a separate macro/template syntax, a good example being the approach taken in the design of ASP (active server pages), PHP, and the like.
Sadly these days, I'm not paid to "solve problems". I'm paid to solve them in C++ —sometimes for good reasons.
I love the Objective-C convention of just using three-letter prefixes for everything. I'll miss its pragmatic approach.
Google has a team and special toolset to do just that.
Also, how to use swap correctly? (Now, with std::move is less relevant though):
template bla-bla {
using std::swap;
swap(result, computed);
}
Sure, I could have guessed this is correct way of using it by myself...It's still ridiculous - calling a function should be easy :(
We had one person in the building who was the PL/I guru. If you really needed to understand something he could work out the answer. Everyone else chose a simple subset of the language and never used the fancy features. Unfortunately everyone chose different subsets so maintaining other people's code was a pain.
C++ has the same problem; big, slow, and a collection of ideas imported from other languages. For example, "concepts" have been proposed for the next "standard". They appear to be lifted from Axiom's Spad language.
The C++ committee seems to feel that "importing" ideas is a way to make C++ into a better, newer "standard". Unfortunately that is simply causing havoc. Forty year old code that no longer compiles because some bright spot decided to change the semantics of "inline" is a huge waste of time.
Forty year old code in Common Lisp, which also has a standard, a single standard, just works. The code is fast because there are years worth of optimizations by the compiler writers.
C++ isn't a language. It is a laboratory where some people work out ways to do poorly what other languages do well. C++ isn't a language. It is a parade of languages with "standards". Do you really want to have to "fix" legacy working code because it no longer works in C++21? Programming is hard enough. Fixing old code because it "no longer conforms to the standard" is a huge, unnecessary cost in both time and money. Use it at your own peril. Just be aware that the code you write today won't compile next year.
Mostly. If not, just
(pushnew :symbolics *features*)
or whatever the code was created on. Especially the very old lisp code regularly needs some coercion to be made run on a standard compliant cl.The "just works" part is proven wrong by the regularly reoccurring attempts to agree on extensions to the standard and the myriads of libraries out there that provide generic wrappers around implementation specifics.
> C++ isn't a language. It is a laboratory where some people work out ways to do poorly what other languages do well.
"Lisp isn't a language, it's a building material." -- Alan Kay
and
"A poor coder can write poor code in any language." -- me
(It's fun running that on modern hardware. It was painfully slow when I ran the original around 1980. Now it can prove the basic theorems of number theory in a few seconds.)
The new C++ features like 'auto' simplify life in new code, which should not have been complicated in the first place. Where life gets ugly is with existing code written years ago. My C++ legacy code regularly breaks. gcc seems to default to C++11 but g++ uses C++14 by default. Breaking 'inline' behavior is just wrong. It seems that the Boost library is partially broken, apparently due to compiler implementation issues. Stop-gap measures, like compiler flags, just make the pain all that more intense.
I'd be quite happy if the standards committee decided to create new languages (e.g. C11, C14, C17, etc) so it would be possible to say "I use C11". As it now stands I don't believe ANYONE who says they "know" C++. Are you up to speed on "concepts"? Even Stroustrop described the last "standard" as "a totally new language".
I studied PL/I, in the University of Maryland dialect called PL/UM, in the 70s as a student. I was very glad that it did not catch on. As C++ grew in size and complexity, I realized that it was this generation's C++ but that it had, sadly, succeeded wildly. If PL/I had been a more well known failure, perhaps the authors of C++ would have heeded it's warning.
I've been programming in C for a long time. I occasionally dig up decades old code and compile it, usually just for fun. Much of the time, I just need to add a few include files, as old C was more tolerant of calling undeclared functions and such. With all of the changes to C, from K&R, to C89, to C99, to C11, it's nice that the core features have been pleasingly stable. The instability of C++ that the OP comments on is one reason I don't like C++ and I'm happy that I don't have to use it often.
The confluence of automatic type deduction, closures, and move semantics turned C++ into the language that it really ought to have always been, given the vision of Alexander Stepanov's STL. I mean really, before lambdas, using the STL was often really clunky.
But even before C++11, the main "killer features" of C++ has always been RAII (deterministic destruction of resources) and compile time duck typing (templates.) These features together have always made C++ an incredibly powerful language that lets you code at a high level of abstraction with zero runtime penalty (at the cost of longer compile times).
Nowadays, C++ can be almost Pythonic in its expressiveness. But I agree that the most urgent problem facing C++ is huge compile-times, which often result from a combinatorial explosion of new types created by templates that instantiate other templates, etc.
(You could probably replace "move semantics" in that sentence with multiple other C++ features and still have a valid statement.)
If you're actually working with C++, old "misfeatures" simply aren't something which gets in your way very often. You can just code in the modern way and be happy.
Every feature/syntax added to C++ is one more place mistakes can happen, and one more thing to watch out for when debugging. I wish there was someone in a position of C++ power pushing to remove a feature for each one added.
This is true, in lots of ways. Lots of code is rushed, corners cut, so was bad the moment it was written. Other code is written in a particular style, and would need to be cleaned up to match a more modern style.
One benefit of backwards compatibility within one language is that these pieces of code can be improved incrementally, without having to switch languages. So, a road to improvement, rather than a source of mistakes.
The key is to make the new code better than the old code!
It is fine to deprecate small warts if there is an obvious semiautomated path forward or if are hardly used (auto_ptr, trigraphs), but things like ADL are very unlikely to be ever fixed completely.
I don't see what's inherently wrong with deprecating and then removing features or standard library templates in newer standards. As long as compilers and library implementations continue to support the old features when you ask for an old standard (by passing `-std=c++11` or whatever), what's the problem if C++26 removes $BAD_FEATURE?
The standards committee doesn't seem to think there's an absolute problem with removing features or standard library templates, because they've already removed trigraphs, auto_ptr, and more in C++17.
It is not just a theoretical issue btw, unfortunately compatibility breaks do happen outside the standard, especially during the early to mid 2000s as compilers started enforcing the standard more closely; enforcing two phase lookup has been particularly painful and I don't think anybody is willing to repeat that experience very soon; there are still codebases stuck on Visual Studio 6 which was infamous for its nonconformance [1] and was widely popular in the late 90s till the early 2000s.
[1] to be fair it parially predates the standard.
Probably would be nasty to maintain for the compiler developers though. Imagine having to do a bugfix for c++11 mode when you just released c++26 mode.
They already have to.
What you're proposing makes much more sense: it means if you write a C++26 only compiler, you don't have to worry about implementing all the old crap that no sane person uses.
The problem then is that some of the advantages of modern C++ are a bit "all or nothing". Just to pick an example, for exception safety in the current sense to really work, basically all of your code has to be written in a certain style, which is something that's really hard to achieve.
Maybe that's less of a problem for codebases started after 2011 that have been written in the modern style from the beginning. But given the way the C++ language continues to evolve, my bet is that even those will eventually run into the same problem with whatever new feature is introduced in 2026. There really needs to be a way to deprecate old language features.
No language that lives long enough is safe from it.
That's one of the things I think the golang project did right. The gofix tool can be used to update old codebases.
As a related question: I seem to vaguely recall some mention by someone on HN, that somebody is trying to get some kind of "safe/strict blocks" markers into C++ (or some compiler? I have the feeling it was to be MSVCpp?), where "misfeatures"* would be disabled. Is anybody aware of something like this? Or was that just a beautiful dream I had?
* -- for some unknown definition of "misfeatures"
You could argue that anyone who wants that is already on Rust or whatever, but I bet there are plenty of people who like modern C++ and don't necessarily like Rust.
These aren't mutually exclusive groups. I'm a professional C++ programmer posting on HN to say that C++ is terrible, even when you can somehow confine yourself to "modern C++" -- presumably because you're free from legacy code originally written in the 00s, or earlier!
C++11 (and to some extent C++14) made C++ less awful, but it's still a turd. And even many of the best features of C++11, like move semantics, are blown away by their equivalents in Rust. By the way, even whenever concepts and concepts finally land (I've given up now), C++ templates are still going to miles behind Rust's trait-based generics in ease of use and readability.
Why?
But these days GCs are much better, and especially with the Go GC having sub-millisecond pauses I think you are right that most projects written in C++ today could be written in Go. (And it seems like that is starting to happen.)
For a number of reasons.
First, it actually works.
Second, a lot of software is written in C++.
Third, availability of third-party libraries and tookits.
Fourth, people do know how to write software in C++, and some even have decades of experience under their belt.
Fifth, it's an international standard, therefore better ensured against bit rot.
Sixth, why should anyone jump onto the latest fad just because?
I seriously don't understand why this myth about "newer automatically means better" is so entrenched in the minds of those just starting out in software development.
Fourth is also a kind of path dependence, but… come on, reasonable programming languages are simple (Lua and 1ML come to mind). Libraries and frameworks take time to learn, but a core language needs a couple days to be picked up, maybe a couple weeks for full productivity. Assuming you knew the underlying paradigms in the first place of course —no Haskell programmer learns Forth in a day.
Of course newer is not automatically better. See the mess we made of the web. Still, it is safe to say that nobody in their right mind would invent C++ today. As Rust is showing, we can do better.
Even so, I'm extremely wary of this "one language to rule them all". Why does the "right tool for the job" always end up being the vanilla version of some popular language? Where are the languages specialists that can tweak your language into something uniquely suited for your particular needs?
Seriously. We call in database specialists, network specialists, security specialists, OS specialists whenever the project has significant demands in those domains. Why are programming languages left out? We breathe with that stuff!
It's not so far fetched to conjecture having one decent high level language to generate that machine code.
I think a good many language designers actually have that as a goal.
Make that feasible goal "two languages to rule them": the high level language, plus uses of the assembly language for some of the inevitable escape hatching. Feasible at least with respect to a given system, and others like it.
However, nothing but one language to program a microcontroller with 512 words of memory, or a parallel cluster with terabytes of storage? Ha ... :)
As for programming tiny devices, no, C++ (or even C) doesn't seem to be the right language to do that because people who should know better routinely do very stupid things in those languages for embedded applications. And it isn't just because they are some cash-strapped amateur: car-manufacturers and name-brand manufacturers of appliances have been shown to not know how to do this. Which tells me that they need languages that can help them do the right thing. Or rather: force them to address typical classes of problems or help them address these.
I even saw a discussion about heap-fragmentation on an embedded system where you shouldn't be allocating memory at all -- which is not only doing the wrong thing, but doing the wrong thing badly. Sure, people should know better, but they don't.
I've spent much of the past two years with my nose in embedded code and if you think the average fullstack programmer produces terrible code, much embedded code is often the stuff of nightmares.
If we are to limit the discussion to larger systems, the number of things where you'd need to use C++ for performance or efficiency has shrunk down a lot. In my experience, the vast majority of performance issues come from bad design, lack of measurement, sloppiness and ignorance about algorithmic complexity rather than the ability to squeeze performance out of hardware. Sure, you can, and should, write extremely performance sensitive libraries that cling to the metal where appropriate, but this still leaves a lot you really should do in languages that provide higher productivity, security and clarity.
> First, it actually works.
It can me made to work, which isn't the same as being a good programming language.
> Second, a lot of software is written in C++.
A lot of software is written in PHP, Cobol and Fortran. That doesn't mean they represent good directions.
> Third, availability of third-party libraries and tookits.
Valid point from a practical perspective, but not from a language design perspective.
> Fourth, people do know how to write software in C++, and some even have decades > of experience under their belt.
Based on a few decades of software development: some people can write good C++, most can't and the majority of those who can't are delusional about which camp they are actually in.
> Fifth, it's an international standard, therefore better ensured against bit rot.
That statement makes no sense to me.
> Sixth, why should anyone jump onto the latest fad just because? > I seriously don't understand why this myth about "newer automatically means better" > is so entrenched in the minds of those just starting out in software development.
That's a straw man.
Instead C++17 will have library hacks like std::variant, that almost certainly will be deprecated for C++20.
I've written too much C++ to be dumbfounded by that stuff but that doesn't mean I'm not still bitter about it.
/s
Modules solve an immediate and obvious pain: unacceptably long compile times. Sum types are more profound. Anyone having tasted an ML derivative (as I have) would dearly miss them. Seriously, once you've tasted sum types, you'll want to use them everywhere: option types, error returns, abstract syntax trees (JSON, XML, compilers…), you name it, sum types probably solve it.
Sum types are no panacea, but if you squint your eyes just right they're pretty damn close.
It is somewhat anathema to the OO idea and brings lots of (runtime) implementation concerns so I can understand the delay.
Backwards compatibility is a strength, up to a point.
That point being actually having to build software that was already written.
Reminds me of C++ itself. Stroustrup posited that it needed syntactic compatibility with C. People had to be able to compile their own code with the new compiler, else his new language would never have been used.
I'm sad to admit he was probably right. He could have settled for linking compatibility, where old modules can be used from new code (and conversely). But that probably wouldn't have worked, if only because nobody wants to deal with 2 compilers and 2 slightly different languages. Also, macros and header files. Seriously K&R, what were you thinking?
Still, this is a possible path forward. To hell with syntactic compatibility, the ability to link the object files should be enough. That would at least let one use legacy libraries with the old compiler, and write the current project with the new stuff. There's just one hard part: the FFI must be seamless.
The problem with breaking some backwards compatibility is that you just broke the ecosystem. And Python3 showed how breaking some is effectively the same as breaking all, and if you are going to do something small, you might as well do it all because its going to be a pain point for years or decades no matter how much automation tooling you build around the transition.
That is made even worse for a compiled language like C++, where if you break headers for some unsupported library it becomes effectively unusable in newer versions.
My Linux system has both installed. Software that needs one or the other just works.
I recently converted my scripts to Python3. I was shocked at how easy it was. Didn't spend more than a few minutes on any given script.
No dependencies that I need that aren't in Python3.
Suppose, I have a silly idea - I could recompile my mplayer+ffmpeg and, perhaps, emacs with clang4 with all the cool optimizations for my cheap crappy i3-6xxx CPU of my crappy Lenovo laptop. Seems like nobrainer. Now movies are less laggy.
Why then wouldn't I recompile my mysql server with -stdlib=libc++ and -std=c++1x, -rtlib=compile-rt, using lld and -lomp? Oh fuck...
C++ is a set of standardized kludges incompatible between standards.
I also agree that type system in C++ is not perfect and is rarely used in a sensible manner. Yet I would rather look for inspiration in functional statically-typed languages rather than in specialized "multi-paradigm" dynamically-typed ones.
Why you consider C# to be dynamically-typed?
Me, I just
static uint32_t
load32_le(const uint8_t s[8])
{
return (uint32_t)s[0]
| ((uint32_t)s[1] << 8)
| ((uint32_t)s[2] << 16)
| ((uint32_t)s[3] << 24);
}It's amortized O(k).
IIRC, the same problem also plagues C's committee.
It is lots of fun with extensions not covered by ANSI C and compiler specific behaviors.
You must be talking about something more extreme, maybe in embedded land? Do you happen to have a small number of f'rinstances?
(Features in a language that one doesn't understand are dangerous. Nobody understands all of C++17. I'll let you reach the conclusion.)
...and yet it's (arguably) the best software-writing tool that mankind has invented, at least up to now.
you mean "the most complicated"? :D