329 comments

[ 2.8 ms ] story [ 309 ms ] thread
For those interested: the two biggest features are probably coroutines and modules.
I wonder how their coroutines compare with rust async await, in expressiveness, performance and ergonomics
One significant difference is that, in my understanding, C++20 coroutines require an allocation. This can be optimized away but is not guaranteed. Async/await will not allocate in Rust.

Superficially, there's also co_await vs .await.

And, really, async/await is a subset of the C++ feature; you'd want to compare against generators, which aren't yet stable in Rust.

> This can be optimized away but is not guaranteed. Async/await will not allocate in Rust.

That makes Rusts solution sound better. But in reality things are a bit more differentiated. Both solutions are not zero cost abstractions for various use-cases. And depending on your use-case one or the other solution might end up being better.

From the user perspective, a big difference is that Rusts `Future`s are lazy (will only do something when polled), while C++ coroutines and the `task` frameworks on top of them are not. Besides influencing the way concurrency can be performed within these environments, this e.g. also has an impact on the stack usage of the solution (Rusts Futures can require a terrible amount of stack just to create the final composed Future).

Then there is the "interface" question. As far as I understand you can have virtual coroutine functions on classes the same way that you can an other functions. But you can't have the same in Rust at the moment. The "async-trait" crate gives you that ability again - but with the drawback that you now have a mandatory allocation (instead of the often elided one in C++).

Overall C++ coroutines are a lot more flexbile than Rusts async/await. The behavior can specified by overriding the promise type, storage type, behavior of co_await, etc. You can make a generator out of it, but also an async function. Rusts async functions are targetted purely at the async function use-case - which might make them a bit easier to understand.

Even within that use-case they are more constrainted. E.g. with C++ coroutines you can do things like "thread-hopping" - `co_await method_that_moves_me_to_other_thread()`. Rusts executor idea wants you to resume your piece of work on the same task (which imho think is nearly always a better idea!).

Another difference is that Rusts "resume/Waker" mechanism is designed for a multithreaded environments - it will take a needless performance hit in a pure singlethreaded shared-nothing environment(think Seastar). With the C++ solution you might be able to avoid that - but at the cost of the framework and language not providing you any thread-safety at all.

std::future/promise is hopelessly inefficient, but the new executor framework being proposed for C++23 does provide for lazy evaluation of futures (or its equivalent). In fact lazy evaluation is the default. Executors can interface with coroutines (although the impedence mismatch is real) and the interface is powerful enough that allocation can be avoided in many cases (not via compiler optimization which I find too fragile), but via being able to inplace construct the coroutine frames in other existing regions of memory.

I was very critical of the C++ coroutine design as the extension interface feels very ad hoc and not built from first principles and because of the hard to avoid memory allocation, but people that know better than me seem to think that it is usable in practice with good performance.

I do believe that thread hopping is quite important in case you need access to remote data and want to avoid mutual exclusion.

Concepts and ranges are pretty big too.
Yeah it's all subjective. On my end concepts kind of seemed unnecessary to me (albeit useful) given you could just write unconstrained templates. In fact I still expect most people to do that a large fraction of the time just due to the diminishing returns. Ranges seemed more necessary but not particularly sophisticated machinery to live without (and I'm curious how much performance impact the templates have too). Whereas coroutines and modules are not only incredibly useful but also quite sophisticated underneath and also quite difficult (or I guess impossible, in the case of modules) to simulate by hand.
Depends on your perspective. Concepts are great if you’re writing libraries and you need to give your user better errors.
Yeah I do expect some very well-written libraries (including standard libraries) to pick it up and use it well, which will benefit a lot of people as these will be widely used libraries, but my guess is most other C++ programmers will not use concepts in nearly as many cases as they hypothetically could/should. Maybe they'll write a few concepts to document the occasional clean interface, but that's about it. The reason being that I expect concepts will have underestimated costs: duplicated logic will not only be frustrating but also get out of sync easily, templates will slow down compilation (it's not like we don't have enough of that already), precise constraints end up being difficult to write, and approximations end up being overly strict/loose and result in headaches for users of a library.

They do seem quite beautiful and useful in theory, but I will be very curious to see how much they're adopted.

> They do seem quite beautiful and useful in theory, but I will be very curious to see how much they're adopted.

For sure! I expect some marquee libraries like ITK to adopt them as soon as it’s prudent (meaning when they can sunset support for older compilers), but most people won’t be using them.

I mean, most people don’t have to even really write templates code...

Oh right, but I meant even by people who do write templates haha. I'm wondering in what fraction of cases they'll actually use concepts when they potentially could.
Concepts are a huge improvement to help new users learn the language. Large, unclear errors are a big put-off.
Concepts are great because we can get rid of all tag dispatching/partial ordering/SFINAE hacks with a more principled (and understandable) approach.
with concepts you also get

    void f(auto x) { } 
or

    void f(Sortable auto x) { } 
as a bonus, which is super neat imho and will reduce the amount of template<> syntax verbosity by a good margin
Concepts will stop people in HN complaining they cannot understand templates. It significantly reduces the template magic in C++ libraries.
These seem to be the four features everyone's talking about: coroutines, modules, concepts, and ranges. Of these, modules and concepts are mostly being praised not so much for adding anything as for removing pain points - super slow compilation in the case of modules and super awful error messages in the case of concepts. Along with ranges, these merely increase parity with other languages that never had these gaps/warts to begin with. The only one of the four that seems like a feature rather than a bug fix is coroutines.

So yay, these are improvements, and welcome just like improvements to any legacy system always are. Kudos to the "maintenance programmers" of language design.

Except for the memory model, rust is loosing a lot of it's competitive advantages over C++ here and more interestingly: C++ is pushing the frontier on what new features/optimizations should a high performance language get. I feel like some of those features will allow new kind of optimizations and it could have an impact on the performance of everyday programs like chromium or Firefox. Of course the adoption will take a few years

I really hope that Rust compiler team will investigate in great depth the expert changes in C++20 and backport the relevant stuff into rust

> Except for the memory model, rust is loosing a lot of it's competitive advantages over C++ here

Rust's memory model is by far its most significant advantage over C++, and it cannot be added to C++ without breaking all backwards compatibility.

Indeed, but there is so much to do on the ecosystem.
Right. Rust is the only of those languages where I feel comfortable handing tasks out to junior programmers and NOT having to hunt for memory errors later in code reviews. That’s such a great reassurance and productivity gain for everyone that it seems hard to go back.

In addition to that it also protects against the majority of multithreading issues - which is something not even available in managed languages like C# or Java.

I don't think Rust is in any way losing anything by whatever is happening in the C++ world. With every iteration of the language it's biggest downside is becoming worse: it's a complex language very few people fully comprehend these days.
> it's a complex language very few people fully comprehend these days

Well I see your point, the reality is that this statement is also true of rust itself!

Not really, it even lost quite a bit o baggage when becoming 1.0.

The features it gets now are all mostly on the roadmap since quite a bit and neither surprising nor do the feel like a huge pile of "everything I can imagine" thrown together.

Rust is several order of magnitudes away become such clogged like C++ is, and also its feature acquisition accelerates slower than the one of C++. The only thing slower than that acceleration is probably its compile speed, but here C++ isn't really better. :)

From observing both since a bit I just really got the feeling that rust adoption of things was more thought out to fit the existing language and ecosystem, not 100% perfect, but much more fitting than what C++ did, i.e., mixing in every thing they could get their hands on, while some actually made things better, a lot just do not go well when being together.

As much as I enjoy Rust, I have to agree with GP. Rust team needed to add a lot of complexity to the language to allow us to solve the borrow checker puzzles, such as Pin, Cell/RefCell, split_at_mut, the list goes on, and keeps growing.

In my modern C++ projects, I only really need to know std::move and std::unique_ptr.

The real question to ask is how much complexity one's willing to pay for memory safety. I'm willing to pay it, but with open eyes about the complexity cost I'm paying.

Until Apple, Google, Microsoft, NVidia, Khronos, Sony, Nintendo, ARM have Rust on their SDKs alongside C++, their communities will keep focusing on C++ for high performance code.
Rust's main competitive advantage is memory safety in a compiled language with native performance.

If you're switching to C++ because of performance, you should have probably picked C++ instead from the beginning.

Maybe it's just me, but if a programming language successfully pushes other languages to catch up or even outdo them in terms of language design, then I would not call that "losing". In the long run we all benefit from that.
Another thing not to be underestimated: C and C++'s build tools and dependency process can be intimidating for new users. Rust uses a configuration file to specify dependencies and compile options, then runs with `cargo run`. This is notable on embedded, where the process for Rust is similar as non-embedded, with the addition of installing a CLI app like `probe-run`, and adding a config file specifying memory available. On C and C++, vendor-specific IDEs (Like STM32 cube) are appealing to configure the build process... and the starting files created with these are complicated, even for `hello world`.
Were the module problems ironed out? I remember reading some scathing criticism of the early designs.
I think that many of the outstanding issues are not related to how modules are specified by the standard, but rather how vendors are going to implement them. Some details that will affect usability and tooling are not baked-in into the standard. In that sense, it's possible that those problems you mention have not been ironed out yet, even if the standard has been approved.
https://vector-of-bool.github.io/2019/03/04/modules-doa-2.ht...

The issue was that there's no language level definition of module implementation and layout so every build system may need to handle every single module implementation differently. The standard body decided to publish a technical report on this issue to ensure some level of interoperability across module implementations.

I can't wait (normal) GCC to support modules!

(it already does but in a dev branch version, not very handy as it requires a full reconfiguration of the environment variables to switch between this and the normal GCC)

The status is here: https://gcc.gnu.org/wiki/cxx-modules

Even as a C++ programmer with too much spare time, it has become obvious that learning and using all of C++ is beyond impractical. To the point where I find that my C++ code more than ever before looks like C.

Nowadays I am using C++ mainly for the high-performance libraries, and only if I can't archive the same in jit-ed python, cython or rust.

The Java strategy of being very conservative about what you add to the frontend would have done C++ a lot of good after C++11 (or even before that).

The notion of using C++ like "as C but with namespaces, std::vector, string and map" is way underrated.
That’s your choice of C++ subset, but the problem with these huge languages is that everyone chooses a different subset to use.

Sticking to plain C has the advantage of probably being the subset of C++ (I know, it’s not technically a subset) that’s in widest use.

I’d add that deciding on the subset is a high cost operation. Design of such a smaller subset-language will likely not be on par with language that is small by design.
> (I know, it’s not technically a subset)

Is it not? I thought C++ was explicitly a strict superset of C?

Syntactically, it almost was; and even this is no longer true today with C11 and later,

More importantly, though - the syntax is not what matters. The languages are very very different in idiomatic use. You just don't write programs the same way with C and with C++. And the gulf between the two only expands with time. A decent C program is almost certainly a poor C++ program, in terms of idioms, utilization of library facilities, and sometimes even in terms of performance (!).

It is not and never was.

Look at for ex. what const means in each, or auto. Or variable length arrays (feature that doesn't exit in C++). Or designated initializers that C++ didn't have for a long time.

Here is a good list of differences: https://mcla.ug/blog/cpp-is-not-a-superset-of-c.html

C++ is almost a perfect superset of old C before C99. There are odd corner cases where prograns are parsed differently, but these are quite contrived. The 3rd edition of The C++ Programming language lists a few cases. Since then, C has had may additions to the language that made it diverge from C++. Your linked article is almost entirely about these new C additions.
Even for the old C it wasn't a superset.

There are plenty of legal C programs that aren't legal C++ - if for nothing else, then because C++ has more reserved keywords which are perfectly legal identifier names in C.

E.g. this is legal C but not legal C++:

int template = 10;

> everyone chooses a different subset to use

I prefer using C++ like "C but with cin and cout" and I informally call it C+ :)

When you add those to the mix you're dealing with destructors, ownership, etc. so I don't see anything wrong with using stuff like unique_ptr/shared_ptr.

And C tends to reinvent object oriented programming with each library so you might as well use language defined classes.

So I don't really see the point.

You don't need to use stuff like concepts, or "showing off how smart I can be with template libraries" (looking at boost), but C++ has a lot of features that make it much more productive than C.

Yeah that's basically how I use it for embedded programming c with classes, raii, better strings, and smart pointers :) . I generally avoid rolling my own pointers and anything much fancier that the simpler algorithms/sorts/etc
Agreed. The bigger C++ gets, the more important it becomes to treat it as "C with some cool extras" and to consider any and all new features as optional extras that you only use if you legitimately need them. The moment you start seeing "C with classes" style as a bad thing, you will slowly wander off into the wilderness.
The vast majority of the real world code a C++ programmer writes day to day is just that.
I think the niche of "more than C, but not C++" is going to be eaten by Rust. It's like C with modules, Vec, String, HashMap, and one standard sensible cross-platform build system.
It might, but Rust still needs to grow a matching eco-system.
Rust has plenty of advanced language features that can entertain the same kind of people who enjoy writing C++ template metaprogramming as a brain teaser.
In practice Go is making inroads in that area. Since Rust has similar complexity to C++ it's not really comparable to C or Go.
Go is a nice language growing in popularity, but it's not a C replacement.

Garbage collection, big runtime, and non-zero-cost FFI are acceptable trade-offs in many areas of programming, but they are deal-breakers for domains where C (or Rust) is necessary.

Rust is somewhat similar to C++ in the feature set, but not in complexity. Rust's features are more orthogonal, without duplication and backwards-compat warts, and you get hand-holding by the compiler.

C is "misused" for a lot of things and Go is a contender in those areas though.

Technically you could be right about complexity vs. feature set, but from the POV of someone that's using a simple language, the two don't look that different. One does help you avoid certain errors, although whether that counts as hand holding or hand slapping is in the eye of the beholder.

I don't know. Rust is still pretty complicated. I'm hoping Zig will have success here as a better C.
And templates, and standard algorithms, and move semantics, and lots of other things that are pretty much necessary in modern code. Well, not necessary, but by restricting yourself from using them you are needlessly:

* creating more work for yourself, and

* introducing bugs in your code.

Don't do that. Use C++ as C++.

If I want all the advantages of that stuff I'll just use rust.
>The Java strategy of being very conservative about what you add to the frontend would have done C++ a lot of good after C++11 (or even before that).

Java lost a lot of mindshare to C# and Kotlin due to that "strategy".

It seems to me that for many developers, all they want from a language is more and more features. I’m grateful for languages like Go and Lua that try to buck this trend.
Yeah, it is so liberating to write boilerplate libraries.
(comment deleted)
(comment deleted)
Just for the HN crowd.

C# still doesn't deliver on all platforms where there is a JVM available, and has yet to even offer something as portable as Swing across all those platforms.

Kotlin really only matters on Android.

In fact right now we are having issues with .NET RFPs, because everything that comes through the door are Java related RFPs.

Not really - Java designers were just plain wrong and it took forever to admit it - things like local type inference (var) made the language pointlessly verbose for ages, and simple features like lambdas made the standard libraries terrible.

There was a 8 year gap where C# users could use stuff like enumerable operators while Java users were stuck in the stone age of writing loops for collection manipulation in a high level language ...

Java designers don't follow fashion, they rather wait to see what actually works when the dust settles and how to keep those binary only 25 year old jars running on modern JVMs.

I have been working with Java, .NET and C++ since they exist, and C# being more feature rich than Java doesn't help if the libraries or OS support that a customer needs isn't there.

C# doesn't follow fashion either, it does things that actually work before the dust settles on them.

I think you'll find many people outside the HN crowd also appreciate their approach over trying to appease the kinds of customer needs that involve keeping 25 year old binary only jars running.

To me .NET Core is a shining example of that

C# has been moving much more quickly since then, async/await comes to mind as a feature that didn't work out
How did they not work out??
Mainly because its the colored function problem. You end up having to change the call stack all the way up to Task<T>. Once you start using them, everything is a Task.
Or polluting the code with a couple of Task.Run() to avoid having to do just that.
.NET Core has been so good managed, that I a project back in the .NET Core 2.0 days to port an application to Java, because the customer wanted to move the application to UNIX (not just Linux flavours), and not all necessary features could be done in Core.

To this day there are plenty of libraries that are yet to run on either Core or outside UNIX.

Plus not everyone is happy how the whole Core, .NET 5, .NET Native, Reunion, UWP, CoreRT, Xamarin, MAUI, Blazor is being managed.

A language alone isn't enough.

I mean .NET Core is targeting Linux, is that really a sign of mismanagement?

And to your second point.. I mean you're comparing concepts at very different levels of a stack. Your list includes a language runtime, a web framework, an OS specific application format/framework?

It's like saying "Java, HotspotVM, JavaFX, Tomcat, Android APK, Vert.X"...

In reality it's ".NET Core and .NET Framework".

And while there have been some growing pains as the term .NET became overloaded, it's always been clear .NET Core is where they want people to be, .NET Framework exists because migration to a new platform wasn't going to happen overnight.

Every year there's more and more .NET Core compatibility, they've done a good job with .NET Core so more people are willing to use it (and port packages to it)

https://docs.microsoft.com/en-us/dotnet/standard/choosing-co...

Naturally I am comparing all levels of the stack, as I mention on my comment a language alone is useless.

Yes, the future is .NET Core, however pretending that outside Windows it can match Java offerings just reveals a complete lack of knowledge of all kinds of platforms that have Java support available for them.

Guys like PTC, Aicas, Gemalto, microEJ doing embedded real time Java, selling M2M devices, IBM and Unisys mainframes, 80% of the mobile world (even if it is an adulterated flavour of coffee), smartcards, blue ray players, healthcare and TV settop boxes, kiosks and plenty of other use cases.

.NET is catching up with 25 years of Java doing cross platform development, while anything that came out of Redmond has been mostly Windows only for 20 years.

.NET Core only supports the three major mainstream OSes, zero support for anything else, and has the growing pains of a platform where plenty of third parties are yet to release anything on Core.

Sitecore just released their first version on .NET Core earlier this month, and I don't see anyone rushing to upgrade.

Doing WPF, Forms? Good luck with many GUI component libraries.

Apparently the designers are going to miss .NET 5 for full stability.

The beautiful thing with being a polyglot consultant is that I don't have to convince myself that I am using the best stuff as "Developer X", I just use whatever stack the customer asks for and then move on.

> .NET Core only supports the three major mainstream OSes, zero support for anything else

This is true, but this level is support for the majority of use cases. I do personally find it very annoying that refuse to support 32-bit Linux tho.

> has the growing pains of a platform where plenty of third parties are yet to release anything on Core

This was true a few years ago, but certainly isn't now. I honestly can't even remember when I last tried to use a library that didn't have dotnet Core support.

I can give you several examples, you can start with Sitecore and SharePoint.
I don't doubt there are examples, but they are surely in the minority nowadays.

Also worth noting that anything built for dotnet framework 4.6.2+ (4.6.2 was released in 2016) will run just fine under Core CLR.

No it won't, because .NET Core doesn't support everything from .NET Framework, like WCF server happily running on 4.7.2.

Here is another example, Oracle drivers for .NET Core only support a subset of their capabilities on Core.

I can keep feeding examples of stuff that is actually relevant for Fortune 500's, which Microsoft keeps out of their .NET Core marketing or just hand waves as yet another porting effort, as if we didn't had better ways to spend our money.

You can keep feeding off examples of the subset of Fortune 500s that refuse to compete for top talent in the wider market and instead try and keep zombie projects shuffling because of their mismanagement using contractors and outsourced labor... they also tend to have the kind of engineering culture that pushes away innovators, treats development as a cost center, and generally avoid investment in any sort of long term growth of their talent...

But yeah, why compete with the rest of the Fortune 500 that hire top talent to build out new systems...

when you can pay a "fixer" who prides themselves on self-flagellation keeping legacy systems with no source targeting platforms designed for computing as it existed decades ago (that only exist because of gross mismanagement and a general view of development as a cost center)?

What's interesting to me is someone would actually try to hold this up this dance as something the rest of the tech industry should aspire to uphold lol. Maybe because it makes for less "war stories" deep in the bowels of decade old systems with no documentation successfully migrated to the latest Jenga block in their leaning towers?

Imagine if other fields worked like this

"Our materials science company prides itself on only releasing plastics that can be molded using what was state of the art 20 years ago"

"Our competitor Macrohard insists on occasionally releasing new plastics that are stronger and cheaper to develop with, but we cater to those shops that refuse to invest in techs who know newer processes!"

> Yes, the future is .NET Core, however pretending that outside Windows it can match Java offerings just reveals a complete lack of knowledge of all kinds of platforms that have Java support available for them.

I have no idea what on earth you're on about... you didn't bring up anything I didn't know as far as places where various JVMs live.

This just reads like another distraction from the topic of language direction just like your last comment trying to confuse web frameworks and language runtimes...

Why is .NET Core supposed to be blindly chase platform parity with JVM down, especially down to embedded devices?

You realize the JVMs used on embedded devices aren't the same ones used on desktop right?

Like there are C# frameworks for embedded development on microcontrollers, why on earth would that be .NET Core's domain? Do you think HotspotVM is running on those smartcard microcontrollers?

-

Your entire comment you seem to be under the impression .NET Core exists to be a drop-in replacement for the JVM for every usage.

Which is especially strange because you're using JVM as a generic term for every JVM in parts of your comment, which would maybe be comparable to the CLR at best (but still be an odd comparison to make)

If anything you're speaking to the strength of C# and a product like .NET Core, they're not chasing the same goals that skewered the development pace of Java.

The C# team is not worried that their language standard changes might be hard on people embedded runtimes in smart cards or 25 year old binary only jars

The same mentality is why C# paid the price to break backwards compatibility on generics back in the 2.0 days, and enjoyed a much more powerful implementation going forward in perpetuity.

You're free to feel one approach is better than the other, but it's non-sequitur at best (and disingenuous at worst) to start spouting off about how the JVM runs on smartcards and so that means .NET Core is supposed to be matching that in a conversation about language growth...

Sure it does, because what is relevant are ecosystems, not language grammars.

Yes, C# the language is better designed than Java the language, while .NET the ecosystem is is tiny spot of Java the ecosystem.

When I mention JVM, I mean any implementation, I don't mix Java with Hotspot.

And yes PTC and Aicas sell full Java SE compliant implementations for embedded development.

The only embedded options for .NET are Netduino, hardly market relevant, and Wilderness Labs, which doesn't cover at all the kind of industrial deployments PTC, Aicas, microEJ and Gemalto are doing.

I work with Java and .NET alongside each other since they exist, so I know pretty well the pros and cons of each platform, specifically outside the implementations that people mix with the language.

> over trying to appease the kinds of customer needs that involve keeping 25 year old binary only jars running

C# doesn’t break too many things while it evolves. Example: https://docs.microsoft.com/en-us/dotnet/api/system.collectio... That class was introduced in .NET 1.1 way before generic, still present in the most recent .NET Core 3.1.

They sometimes deprecate higher-level stuff, but very conservatively so. E.g. asp.net web forms (2002) is deprecated, while windows forms (also 2002) is still supported.

Try to run random .NET Framework Assemblies on .NET Core or .NET Native, this is what Java philosophy tries to avoid.

Forms designer is still broken on .NET 5, and it might not make it to the final release.

This is a single breaking jump after 20 years. This migration is really needed and well considered.
I've never had anything but problems trying to run Java apps. Maybe in server land it's been great but in desktop land, outside of Minecraft, it's always been hell for me.
> "Java designers don't follow fashion, they rather wait to see what actually works when the dust settles and how to keep those binary only 25 year old jars running on modern JVMs."

Yup, for better or for worse, Java will be the COBOL of the 21st century.

Apparently 21st century developers don't have much issues dealing with UNIX and C, just about 10 years younger than COBOL, speaking of which, both about 30 years older than Java.
One can be staid and stale at any age.

Aside from that, the average 21st century developer would have a meltdown trying to use C.

It's a feature, not a bug.

Java is stable, and evolves with a huge amount of thought (they employ theorists to model the impact of changes to the Java language even.)

The benefit of this is a long-term platform, and an excellent implementation. Due to this Java has become the platform where the majority VM research is done, which means Java has many excellent state-of-the-art garbage collectors and a JIT a level beyond that of C#.

>which means Java has many excellent state-of-the-art garbage collectors and a JIT a level beyond that of C#.

Unfortunately this isn't enough to make up for the latency hit from not being able to directly stack allocate things like C# allows (especially with its recent addition of Span<T>).

> make up for the latency hit from not being able to directly stack allocate things

Java does better than direct stack allocation - it does automatic scalar replacement instead.

Can automatic scalar replacement turn my ArrayList<Pair<Long, Double>> into the equivalent of std::array<std::pair<int64_t, double>, N> (or Span<Tuple<long, double>>)?
It doesn't turn it into the equivalent of another data structure, and it doesn't allocate it on the stack, that's why it's better. It turns each value in the collection into a dataflow edge which then goes into a register, or the stack, or anywhere.
This seems really interesting, do you have any sources I can look into for more information along these lines?
so does any decent compiler. But to do that in java you first have to prove it is safe, which is hard.
Java has a long history of saying “we don’t support that feature because it’s d-a-a-a-angerous.” Personally, I think that’s an insult to Java programmers, but Java programmers don’t seem to take it the same way. They’re happy that somebody at Sun or Oracle is able to keep all the sharp corners away from them.
So...if somebody hands you responsibility for a codebase, you're happier when the language has sharp corners and bleeding edge scars?
I’m annoyed that things aren’t “complex,” “brittle,” “difficult,” etc.; they’re just “dangerous.” They’ll draw blood through the computer screen. I know programmers who have actual fear of pointer arithmetic even though they have no idea what it is.

To be fair, Java has a lot to recommend it. For one, there are, of course, an incredible number of packages available to build off of. But I find it incredible that the language that replaced finalizers with phantom references still says pointers are too dangerous for programmers.

You know, coming from Java and seeing new languages like Go say the same thing except for features that Java had essentially forever is just maddening.
Java has state of the art garbage collectors because java programs are state of the art garbage generators.

JVM is not the best in all areas.

Even then they fumbled the execution. Why on earth would they make streams without support for native types?
> local type inference (var) made the language pointlessly verbose for ages

I guess that this is a question of taste.

What for you is "less verbose" for me is more confusing to read. I like to see the types as they complement variable naming. To avoid typing a few letters the code will for ever require me to double check the types with help of the IDE.

I have worked in medium sized corporate companies. The code base is quite big and one of the 20+ development teams may get transferred a project from another team (does not happens super-often, but it happens) or they may create pull-requests for bug fixes (this is more common).

Clear and easy to understand code is life saving. In one of the companies I worked for a Javascript team send a -1 instead of a "-1" the cost ramped up the hundreds of thousands of dollars and our clients were not happy about it. Rollback mechanisms were used as fast as our clients detected revenue problems on their own customers.

And the tests did not got the error as the values is used at the integration layer between our clients and us.

I see safety an increasing value as our programs control more and more money and more and more services. And, I have to admit, I feel more comfortable with more verbose code.

Did you spend any significant time working with C#?
> Did you spend any significant time working with C#?

I have no experience with it at the corporate level. There, I have seen, it mixes a lot with .NET. So, I guess that the corporate equivalent to Java is "C#/.NET".

I spend some time several years ago with C# in Unity3D, thou.

I really liked the C# language. I found the Auto-Implemented Properties a neat compromise between encapsulation and verbosity (Verbosity has no value if does not add information).

Java is trying to be everything to everyone and that is a mistake. I liked Java more in the past, and I would have added just a few things from the past iterations of the language (e.g. Modules is a good idea that actually simplifies the language and moves much code to "frameworks" instead of being part of the core language).

C# seemed more focused on its initial style were Java is stretching all over the place.

You haven't used much LINQ, pattern matching, spans, ranges, default interface methods, non null references in C#, I guess.
You are right. I see that some of that features were added much later on.

For non null references, I used to work with C++ and I really liked some of its reference/pointer/smart-pointer semantics even that everything can be used also really badly.

I have done some basic training in Rust, and I am happy to see that it seems quite close at the way I was using C++.

But, I see C# in the future replacing part of what Javascript does nowadays once WebAssembly takes off. I would like to learn more about that.

You just need to use var properly. I.E. only when you can tell the type from the rvalue.

var a = new ArrayList<T>();

not:

var a = o.getThings();

> You just need to use var properly.

That is a very good point. I find the diamond operator more of my taste as it requires you to think if you want to expose ArrayList or List.

List<String> list = new ArrayList();

But, as you point, the second example removes information that will require to spend time to check types each time that someone reads the code. I do not like that.

I use auto-complete and I type quite fast, so, I do not see to write code as a problem. I spend most of my time understanding the functional needs, looking for better patterns or algorithms to implement performance-critical sections or finding names for exposed APIs that state clearly its function when I "write code". But, most of the time, I am just reading my old or other people's code to just change a few lines or decide on a local refactoring.

^This

Here, the first is much less verbose, but still clear:

    var x = new Dictionary<string, MyComplexType>();
    Dictionary<string, MyComplexType> x = new Dictionary<string, MyComplexType>();
But here, it’s ambiguous what the type of `x` is without Intellisense:

    var x = y.GetStuff();
(comment deleted)
Pointless typing and verbose code has nothing to do with writing code - it's all about code being readable.

Java type declarations can be 20+ characers - just scanning through the code and having to skip all that junk makes my eyes more tired reading through. Types are implicitly deducible when you know the codebase 90% of the time (and should be added when they are not), and if you don't know the context you will be slow no matter what.

> when you know the codebase

Yes. When I was younger I worked in solo projects. I knew my code almost line by line.

In my last decade, in middle sized companies, nobody knows all the hundreds of micro-services code. And code changes while on vacation, that can be 6 weeks of the team working without you. That is not ideal, but in such a big code base it is difficult to have everyone reviewing all the changes on a single micro-service, impossible to have all 20+ teams reviewing all of each others code.

Different problems need different solutions and code styles, I guess.

My point is that in a good code base types should be obvious from context. If you don't know the context then you will be slow (and make a lot of mistakes) no matter what the type say because you'll likely misunderstand the domain logic (context) unless it's something trivial. I would hate to work somewhere where I'm expected to randomly drop into micro services I didn't have anything to do with and debug/support them - sounds stressful.
Swing is a horror show from both a developer and an end-user perspective, don't know why you would even mention that. Windows desktop apps based on Forms or WPF are in another league both in terms of ease of development and user experience.
Swing is only an horror show for those that don't bother to read books like "Filthy Rich Clients", or don't want to spend money on a proper design team.

Why do I mention? Because until now .NET Core still doesn't have anything like Swing across all supported platforms.

MAUI might do it (Xamarin renamed), or you might just get Blazor running on WebWidgets.

I rather have Swing if the alternative is running Blazor that way.

Not counting community toolkits here, just what is available out of the box.

I worked a bit for a project that tries to make Swing Application to touch friendly. There's almost zero support for touchscreen.
But that is not inherently a bad thing.

If we look at programming languages as tools, it makes sense for them to get out of date and new ones taking their place, with all the lessons learned.

So its possible that programming languages like C++ that keeps extending their own life through adding features (while keeping weaknesses), will ultimately cost the community/industry more in the long run.

I'm not saying Java should have introduced ground breaking features - I'm saying they made design mistakes that they should have corrected far sooner (var/type inference) and refused to add some basic features (lambdas) that would have made the code a lot better for it.

They did add those features eventually (Java 8) - about 8 years behind C# (since C# 3.0)

>If we look at programming languages as tools, it makes sense for them to get out of date and new ones taking their place, with all the lessons learned.

Part of me thinks that this is how it should be. Extending a language constantly while providing backwards compatibility can lead to some awkward syntax too.

Agreed.

Just gonna drop this here: Nicolai Josuttis “The Nightmare of Initialization in C++” [0]

[0] https://youtu.be/7DTlWPgX6zs

The thing is that this is not a huge issue in practice. I stick to uniform initialization in 99% of cases and it works out pretty well. I have far fewer bugs from initialization screwups than from other things.
But what kind of an effect does this have on someone new learning the language? It seems to me like it would make it slightly harder to learn and get used to.
Simple, read and religiously follow the Core Guidelines. Bad, converting initialisations are also flagged as warnings (or errors with -Werror).
So C# definitely benefited with the second mover advantage. It learned a bunch of lessons from Java such as:

- No checked exceptions

- Properties (I wish Java would add this to the core language instead of relying on things like Lombok as it shouldn't change the IR and really is just syntactic sugar)

- Partial classes. This really isn't in contrast to Java because Java has nothing like it. But it is a neat feature for partial code generation;

- LINQ. Java eventually added streams but last I checked it still had performance issues and IMHO LINQ is just cleaner;

- Conditional compilation. This is really a huge oversight. One of the huge benefits of the preprocessor in C/C++ was conditional compilation. It's great than C# included it. It's bizarre to me that Java hasn't.

- Async/await. Honestly I still find C#'s version of this more awkward than Hack's. Experience has taught me that whenever you spawn a thread, you've probably made a mistake as subtle mutlithreading bugs are the devil and cooperative multitasking like you have in Go, C# and Hack is usually far safer and sufficient most of the time. Still, C# is still better than Java here.

- C#'s reified generics vs Java's type erasure. I think it was the right decision to break backwards compatibility here (and I don't usually say this). This was pretty early too (IIRC generics were added in C# 2.0).

But all that being said, I still think Java has a large mindshare and install base than C# by a mile. it's not sexy so it gets less attention on HN but Java is still massive.

As for Kotlin? Much like Scala I see this as nothing more than a curiosity. Android developers seem to like it but I think it's a tiny fraction of Java still.

> As for Kotlin? Much like Scala I see this as nothing more than a curiosity. Android developers seem to like it but I think it's a tiny fraction of Java still.

Java is massive for legacy reasons, but would be nice to have some statistics regarding new projects. The last two companies I've worked for had backend teams using Kotlin so I've been assuming this is also preferred by backend people. Could well be that this has was an anomaly though.

I mostly develop for Android so my own perception is obviously biased, as Java is pretty thoroughly erased from this world now.

Easy, JVM == UNIX == Browser, Java == C == JavaScript.

Anything else on the JVM is nice to have, but isn't where all the goodies are.

Google has a special interest in getting rid of Java, hence Kotlin.

In fact, it is going to be fun to watch how they will keep up with the pace of the JVM, because when the majority of key libraries move to modern Java, many of them will stop being compatible with D8/R8, forcing Android developers to use pure Kotlin libraries.

Then JetBrains needs to think how to make use of Java libraries that use the new FFI, virtual threads, inline classes, generics, SIMD vector types, while keeping the language compatible with what ART is capable of.

And now Java is benifiting from being a second mover on a lot of the features C# adopted.

See virtual threads vs async/await. Java's version is going to be better.

I always end up with a couple of Task.Run() calls, because cannot change the complete call chain to deal with async/await.
Even that situation, you can still use await inside Task.Run, it should be useful than nothing.
If you want to avoid changing the complete chain to Task, there’re workarounds.

You can block the caller thread waiting for the task. Deadlocks are possible with this approach due to synchronization context shenanigans, but they’re easy to fix, VS debugger is quite good at multithreading.

Another method, you can run whatever dispatcher on your main thread, in modern .NET that’s usually Dispatcher.PushFrame.

Also, if the async method returns no values, you don’t need to change the call chain, you just need to catch and handle exceptions.

(comment deleted)
LINQ is cleaner, but I find streams to be more elegant when considering the language as a whole (its just a pure library - no new syntax/rules/etc to learn).

I feel like a lot of languages these days trend towards "kitchen sink" languages that toss in everything and the kitchen sink in the name of clean looking code. IMHO this tends to sacrifice language elegance. This is probably why I tend to like languages like Java/Go/Clojure.

There is not new syntax for LINQ either -- it's just fluent-style via extension methods. I don't know many people that use the SQL-like syntax any more -- and it only covers a tiny amount of the functionality.
Honestly I've forgotten sql-style LINQ exists. Method-style is common.
“One of the huge benefits of the preprocessor in C/C++ was conditional compilation. It's great than C# included it. It's bizarre to me that Java hasn't.”

The C preprocessor can make it way to easy to break code, for example when it is used for feature flags and/or multi-platform support. If you have N feature flags, you have to compile 2^N different programs. Multiply by M for supporting M platforms.

It also makes it impossible to check whether source code can be compiled. The text inside a

  #ifdef FOO
    ...
  #endif
block doesn’t have to be valid source code, but the compiler cannot know whether it has to be. I think that’s why Java ditched it, and I think that makes sense. Adding a more limited feature, like C# did, makes sense, too, though. I’m not sure C#’s variant is limited enough, though. it still is subject to that 2^N problem, but gets saved from its main problems because C# isn’t running on as diverse environments as where lots of C code evolved.
But the 2^N problem exists no matter you like it or not. Except now it's done at runtime with dependency injection instead of compile time.
That’s true, but it is done a lot cleaner than in the wild west days of the C preprocessor, where feature-specific, compiler-specific, and platform-specific #ifdef’s were sprinkled throughout the source code seemingly without much thought (but keeping things working must have taken lots of thought), nested #ifdef’s were common, and often not all cases had separate paths in the code.

Dependency injection can be made messy, too, but that takes more of an effort. You can also test injected code in isolation. That may take some effort, but those preprocessor messes only could be tested as part of the entire product.

As I said, I can see why they wanted to get rid of that. Not adding a same replacement may not have been the best choice, but I am not sure of that. Programming culture also had to change, and that sometimes requires drastic action. Apple also did that in the Mac by not providing any text mode (forces programmers to make windowed applications) and by removing cursor keys from the first keyboard (forces programmers to provide a good mouse interface)

Some circles rely on Lombok, I never used it nor plan to.

I rely miss checked exceptions on .NET, specially with libraries that provide zero documentation about their exceptions.

I've never seen the allure of lombok.

Most things shouldn't even have getters and setters apart from your @Entity classes.

> due to that "strategy"

People put scare quotes in seemingly at random these days - are you suggesting it's possibly not their strategy and actually they're lying? What do these scare quotes mean?

They are saying is not a very strategic strategy
I think Java took it too far. If they'd innovated at even 1/2 the rate of C#, I think they wouldn't have lost as much mind share.

But of course, I'm sure Oracle is a big reason too.

Oracle is all the hate, but when it comes to java, Oracle really got the show rolling again. Prior to Oracle, little happened. After Oracle, a lot is happening.
Oracle haters seem to disregard that Oracle was the only company bothering to actually make an offer and keep it, without that offer, everyone would be busy maintaining Java 6 codebases, or porting code to something else.
IBM?
IBM withdrew their acquisition offer shortly thereafter.
Why does this post need to appear any time C++ is a topic? Do you learn and use all of any language you use?
Because there is this urban myth that other languages aren't as complex, yet drop someone with a beginners loved language like Python 3.8 and they will have fun throughout the almost 2000 pages of documentation plus all major libraries in use across the ecosystem, and Python implementations.
Other languages are definitely less complex — you generally don’t see language lawyering for Python or Java — but I think that there are many useful features in C++14/17/20 as well. Writing only C++11 will lead to suboptimal code.
> you generally don’t see language lawyering for Python or Java

But my experience for instance when having to do stuff in C#, Java or Python is that when I'm looking for advice on the internet, stackoverflow, etc etc... 80% is reaaalllly bad, in the sense that if it were C++ everybody would be screaming "wtf don't do that this is insane" and write 12 blog posts and 40 twitter flamewars about why this is a bad idea and you should never ever do this... but apparently the "tolerance to bad code" is much higher in other communities.

One way Herb Sutter looks at it is — most advanced programmers could probably write a Python or a Java interpreter. It might take them a few years, and they might struggle with some complex language features like metaclasses, reflection, or the type system, but the language spec is understandable enough that it’s feasible.

But give them five years and they would generally not be able to write a C++ compiler.

This is a side effect of those languages being much more accessible to beginners and more widely used than C++.

You won't find that as much for for Haskell or Clojure or Brainfuck but that doesn't make them better languages or less tolerant to bad code.

Being more accessible means being usable by less trained/skilled developers, which makes online communities less trained/skilled on average. I wouldn't use that as an argument to prefer to use worse tools and their built-in 'you must be this tall the ride' nature.
The problem is not just complexity, but complexity with tons of pitfalls.
There are plenty of opportunities for a Python Puzzles quiz.
Are you seriously arguing Python has about the same complexity as C++?

An extensive standard library is not the same at all as an large base language size. Adding a million books to a language doesn't make it more complex, adding a million words and verb conjugations does.

Yes I am, Python even changes stuff between minor releases.

Also I think many aren't aware how powerful Python actually is.

Totally agree. Look at something like asyncio and how many things have been improved or deprecated since 3.5. it makes it really hard to keep up. Sure, if you want to stick to basic python it's certainly easier to learn than C++, but the language as a whole isn't much simpler
I have spent quite a bit of time invstigating the metaprogramming capabilities of python and I have barely scratched the surface. And I hear they have added a fully parametric type system recently...
> yet drop someone with a beginners loved language like Python 3.8 and they will have fun throughout the almost 2000 pages of documentation plus all major libraries in use across the ecosystem, and Python implementations.

I would agree that the Python ecosystem is as complex as the C++ language.

I would not agree that the Python language is as complex as the C++ language, or that they Python ecosystem is as complex as the C++ ecosystem.

I will agree also that the Python language has very comprehensive first-party tutorial and reference documentation, but that doesn't add to the complexity.

Then it is time to learn some clever use of Python metaprogramming, metaclasses, how slots interact with old style attributes, old and new style classes, clever tricks with magical methods, stackless vs regular Python, multiple ways to format strings, arithmetic semantic changes,...
> old style attributes, old and new style classes

pretty sure that's only a factor if you need to deal with Python 2

I expect any Developer X, to comfortably understand a random codebase of language X.
I was aware of all those things when I made the original statement, thank you.
(comment deleted)
I think the two major c++ documentation websites are far better than the official Python documentation. They have more examples, the different variants are clear across which version of the language you are using, and I never need to go elsewhere. Python documentation is typically lacking many of the examples you'd really want, and you need to go elsewhere to find those.
> Do you learn and use all of any language you use?

Generally, yes for Python (definitely for 2, async shook up 3 a bit), C (barring a few genuinely legacy things like trigraphs), Go, Lua, and I think probably at least 2-3 times a year for anything in Java 12 and earlier.

C++ is the only language I use regularly that I am certain I don't even know of, let alone know or use, all the features of.

> Do you learn and use all of any language you use? yes for Python

Have you really used all of these Python features (from https://twitter.com/raymondh/status/1280988785841278976)?

__class_getitem__, __init_subclass__, __prepare__, __qualname__, __slots__, __spec__, __annotations__

__subclasshook__, __abstractmethods__, __text_signature__, __index__, __loader__, __mro__

I've been writing Python for years, but I've never even heard of half of them.

Because they are extension points that all have sensible defaults (in most cases, "nothing to see here") but are readily available when one needs to write something magical, not because there's unnecessary complexity in the language.

All Python-like languages have the same or similar mechanisms (for example, a method resolution order whenever there is multiple inheritance) and they are usually not explicit and not customizable.

But the common argument against C++ is that you need to know a large portion of the language because someone somewhere might be using it, and you may have to read and understand their code. So even things that are optional in python should count against python, just like they do in C++.
The difference is that C++ features very much interact with one another in subtle and detrimental ways, so if you are using feature A and a codebase you leverage uses feature B, the interaction of the two can genuinely cause issues. For Python, the extension points are generally hooks into very explicit operations (and some of the symbols you list aren't even extension points).

Hell, the very defaults of C++ will interact badly with other features and proceed to shoot you in the foot, as Chrome somewhat recently reminded us (https://chromium-review.googlesource.com/c/chromium/src/+/16...).

You need an 8x6 matrix just to know what the compiler will or won't generate (https://i.stack.imgur.com/b2VBV.png) and then you need to know exactly what the defaults will do and whether that breaks your object entirely and you need to override those defaults.

Oh I completely agree. I am mostly just annoyed at the slanted comparisons, saying that something like Python is ”simple” on some absolute scale.

I teach Python to scientific programmers. There are a lot of little details and corners that aren’t as obvious to experienced developers. Just like any language.

Nobody in the thread said that Python is simple though, only that it's nowhere near the complexity of C++.
There is a big difference between "optional because I don't need do to the thing in 99% of projects" and "optional because I can use one of three alternate features with subtle incompatibilities to do the thing."
The only one I had not heard of before is a relatively recent addition, __class_getitem__. To Python's credit, I immediately (and correctly) guessed what it did from the name. I have used over half of them - if you have even written anything that needs to show docstring/typing information or a plugin loader you already cover nearly of them. I've used __index__, __slots__, and __mro__ more times than I can remember. The ones I haven't used are mostly because they are Python 3.4+.

But, critically, you won't find anything other than __slots__ and __index__ (and maybe __subclasshook__ if the code you're working on was from someone who drank the ABC koolaid back in the day) in "normal code" - they're there for people who want to hook into language internals, the kind of thing you'd usually find #pragma'd in C++.

With C++, on the other hand, you run into this kind of complexity just trying to solve "ordinary" problems. And it bears repeating, the "safe subset" between projects is different. It's not the only language with this problem (Common Lisp suffers greatly from it), but it's the one that offers the least in return and breaks the hardest when you get it wrong.

> C++ is the only language I use regularly that I am certain I don't even know of, let alone know or use, all the features of.

I'm still holding out some hope that Stroustrop releases a new edition of "The C++ Programming Language" with the features from C++14 onward.

Kind of ironic that I would agree with you. The reason I still wrote it is that my opinion just recently changed from liking C++ but understanding the pitfalls to a more pragmatic this is not worth the time or effort.
Drop someone in front of C# 9, Java 15, Python 3.8, Typescript 4.0, Ada 2012… and watch how they manage.
Java 15?! I hardly realised they'd moved past 8.
New version bumps after 8 are not necessarily major.
Yep, some people love their outdated GC algorithms and JIT implementations.
(I think all they meant was "non-breaking" not "non-useful.")
>Nowadays I am using C++ mainly for the high-performance libraries, and only if I can't archive the same in jit-ed python, cython or rust.

Is anyone aware of a library for another language that's as fast as Eigen?

This is a hard comparison because pretty much all of these libraries call a BLAS implementation under the hood, so what you might be comparing is actually the cost of stuffing the array with your data in each language (which is obviously task specific).

I think it'd be difficult to argue one way or another: Eigen gives you flexibility one way (custom kernels) and Python gives you another (interactive debugging and easy visualization). Cython/Numba make it even more muddied.

I can definitely takes the cake for an easy to use syntax for doing all kinds of linear algebra. It's only able to do that because the extensive operator overloading that C++ allows. However, don't want that for you for a speed. Using something like MKL directly is always going to be faster than eigen. The trade-off is the API is much more complex.
C++ is not a "language for all things". It's a tradeoff of features, and that's ok.

However, the idea that you should learn and use "all of C++" is a mistake to begin with. It's something that sort-of happens with C, but doesn't really make sense with larger languages.

Specifically, remember that C++ is _multi-paradigmatic_ - you can write more object-oriented code, functional code, highly templated generic imperative code, or, well, C-style code. The standard library also now has something for everyone, and there's no reason to know _all_ of it.

On the other hand, many things which used to be difficult to write and required some deep "voodoo" or a lot of boilerplate are easier and more straightforward these days.

C++ looks more like a union of many other languages than anything else I know of. Forget the old joke of mimicking Common Lisp, C++ is a hacky implementation of all other programming language.

It is quite marvellous in a way, almost a statement of "we don't want design, we just want something that compiles". It has worked out remarkably well in practice.

> it has become obvious that learning and using all of C++ is beyond impractical.

Doesn’t really make sense why you’d want to anyway. Why would you want to use all of any language? C++ offers so many features because of its extraordinary flexibility and application to a wide range of domains. Unless you’re writing an app that is a game that also trades high frequency transactions on the financial exchange, while performing physics simulation and 2-D vector rendering, all while serving up a Web server, it would not make sense why you need to use all of the language. It’s perfectly fine to find those parts of a language that you are personally interested in.

The set of features a language provides is part of an unwritten contract:

We write our code such that it minimizes the amount of effort to read it, under the assumption the reader knows the language.

This way, it makes sense not to use a library for something that can already be cleanly expressed by the language because this introduces additional mental overhead for the reader.

Yet is doesn't make sense to avoid modern, simplifying language constructions, as we can assume these are known by the reader.

This unwritten contract is jeopardized by an overload of language features, as suddenly we may want to avoid certain features considered complicated. Hence, the notion of optimal code becomes more subjective.

It becomes a problem when using code written by other people. Since everybody is using a different subset of C++, a project with external dependencies quickly becomes a hodgepodge of different idioms, coding practices and language subsets and as a result becomes harder to maintain. Some of the language features are incompatible with others (e.g. using exceptions for error handling vs disabling exceptions for performance).
Pretty close to none of the things added to C++ over the years are specific to certain kinds of problems. It's not like you can't write a game/hft/physics/svg rendering perfectly well in C.
All of the work on compile time programming in the last few versions is definitely for performance-oriented domains (certainly others may choose to take advantage of it as well). If you don’t need that kind of performance or don’t need to have complicated logic run at compile time to save on those runtime costs, those features may not be so necessary for you.

And there are definitely things that these features provide that are impossible in C.

I find I need to learn it all because I write code that interacts with other code. I find myself reading example code that uses advanced C++ constructs, or sleuthing though a 3rd party library to understand it. Every time I find a library with a "modern C++" take on a problem (json parsing, etc.) I know I am going to have to dust off my knowledge and even learn something to make use of it. Very high cost. It is just a tough ecosystem to exist in as somebody who isn't 100% c++.

I remember starting out with Python and only knowing a subset of it, but as soon as I started writing real apps that interacted with the larger Python ecosystem, I found myself having to learn the full language (or at least a lot more than I did writing my own isolated code).

All the template SNIFAE stuff hidden in highly generic libraries for is going to become quite simplified with C++ 20 concepts. Also, to be honest, it wasn't _all_ that complicated as long as you kept a few patterns in mind.
I think my objection along those lines, if I were searching for one, is not with the quality of what is being added but with the fact that it takes effort to keep up with them.

C++11 introduces hugely useful stuff. I would much rather have it than C++03, c++98, etc.

Whenever I come across things introduced in 14 or 17, I usually evaluate it and say, that addition makes sense, maybe it should have been there sooner. But I am not actively seeking out that information. So I am never up to date.

It is a big contrast from a few decades earlier, where you would expect to use very few new features from the standard for a period of many years. That is also the expectation the C standard gives: it hasn't changed substantially since 1999, and even that you could call relatively minor since 1989. But I still think they are doing a good job with modern c++, even if these old expectations are no longer the case.

> learning and using all of C++ is beyond impractical

I agree in general, but still, some of the newly introduced features are actually awesome. Here’s ones I’m using almost every day.

C++/11: initializer lists, range-based for loops, strongly-typed scoped enums, raw and UTF8 string literals, thread_local, thread synchronization classes including atomics, alignas

C++/14: binary literals

C++/17: if constexpr, std::string_view, better static_assert

And in C++/20, pretty sure I gonna use std::span and std::bit_cast.

In C++ we don’t pay for features we don’t use. I’m totally fine with other people getting the features they want (despite finding them unreadable and overcomplicated), I simply don’t use the stuff I don’t like.

My objection is lot of features are being added as library features in ad-hoc ways. The old "if it can be library, it should be library" fallacy.

The classic example is C++ ranges' pipe operator. If it was implemented in language, like OCaml and Elixir do - There would have been no need to write range adapters - the error messages and debugging could be much better than 100000 line template implementation. - debug build would be fast as well - compile times would not suffer

Implemet-it-as-library is often a leaky, brittle abstraction. That's the reason LISP, with its proclaimed magic capabilities, didn't take off.

The C++ committee seems quite academic at moment. Last time I read C++ performance report, all I could find was some old advice like "use list if you want insertion"™. They didn't mention difficulties in using realloc in vectors. They didn't mention inefficiencies in stl HashMap implementations due to iterator invalidation constraints. They didn't mention exceptions requiring dynamic storage and RTTI. Note that many of these problems are not yet fully solved with move constructors.

At the same time they are also less academic than required. Given how they managed to put pipelines into an ugly template library without any of the considerations I mentioned above.

I can't help but I feel similarly towards all standards committees. The JS standards people are still unable to deliver a standard library, and a "use strict"-like flag that enables easy tree-shaking.

If anyone here is in C++ standard committee, you owe us an answer.

> Last time I read C++ performance report, all I could find was some old advice like "use list if you want insertion"™. They didn't mention difficulties in using realloc in vectors. They didn't mention inefficiencies in stl HashMap implementations due to iterator invalidation constraints. They didn't mention exceptions requiring dynamic storage and RTTI. Note that many of these problems are not yet fully solved with move constructors.

The TR18015 (Technical Report on C++ Performance) goes into details on most of the above (and much more) and it was written in 2006. The only thing missing is a discussion of hash_map as it wasn't part of the standard yet.

Finally concepts !

But the module spec feels a bit weird ( https://isocpp.org/files/papers/n4720.pdf ).

I mean, "import M" should create a M namespace with the imported symbols. Here, it's more like "from M import *" in Python.

C++ already has namespace for that.
Python collapses the name of the module (usually the name of a file) and the name of the "namespace" on the importing side, while C++ modules add a level of indirection by specifying arbitrary namespaces for module content (independent of the name of the module).

Evidently, the complexity of finding the same namespace in multiple compilation units has been considered acceptable for C++ modules because it was already handled decently.

This fixes so many long-standing annoyances! Modules at last. String literals as template parameters. Ranges! C99 designated initialisers! Can't wait to be able to use this in about 5 years :-D
You can already use 90% of this with a compiler flag.I used concepts years ago
Looks like most of these features are already supported by the major compilers. A few might be hiding behind a flag or three but I expect them to be defaulted soon.
Right it's probably fine for hobby projects but for commercial projects you have to wait until it's supported on all platforms and the majority of your customers are happy with you using it. It can take a long time (e.g. std::optional was only supported on Mac in 2019ish).
Cool that real modules are now official. Preprocessor textual inclusion should have been left behind in the previous century!
The preprocessor is not gone. It still exists in the context of modules. Figuring out the details of that interaction has been a major issue when defining modules and the result is quite complex.

I doubt that we will see clean modules that are free of preprocessor shenanigans, especially when writing any non-trivial portable library. I am no prophet, but I currently assume that unless we get hygienic module friendly macros and better conditional compilation on a syntactic level than dumb textual #ifdef, modules will only end up adding complexity in practice.

The biggest reason that macros are not going away is backward compatibility (a very important reason of course). Adding hygenic macros or "module friendly" macros would not help one bit with that.

Also I belive that macros do not escape modules by default. That's a huge improvement.

I've left C++ for C (and Python, and K, and others) somewhere around 2007 when it only started getting crazy. I sort-of keep track of the changes to the standard like lambdas, without which you can't read modern code.

But assuming I lose my sanity again and decide to go back to doing C++, which resource would you recommend for properly catching up the last 15 years of C++ changes?

Bjarne's Tour of C++ 2nd Edition book.
Seconding this. It's a very clean and accessible overview. If the code examples in it were your only exposure to C++ you'd never guess how much of a mess things can turn into "out there" in the wild.
Tour of C++ by Bjarne Stroustrup as others have mentioned.

Effective Modern C++ by Scott Meyers (esp. for the chapters on smart pointers).

Arthur O' Dwyer's "Mastering the C++17 STL"

David Vandervoode and Nicolai Josuttis etc.'s "Templates the Complete Guide"

The first chapter of "Elements of Programming" by Stepanov, and maybe the rest if you want.

I think also, just kinda glancing over the spec.

Bjarne's paper on the evolution of C++ from 2006 to 2020 is also important I think: https://dl.acm.org/doi/10.1145/3386320

As for talks, https://www.youtube.com/watch?v=XS2JddPq7GQ is great for value categories and move semantics

https://www.youtube.com/watch?v=St0MNEU5b0o&t=6s also move semantics, and also part 2 of that if you want

I'll add more talks here in a bit!

And honestly if you've liked C, you can get far by just starting with that then slowly adding things you want. I think the first things one may end up reaching for are std::vector / std::string etc.; then being able to attach methods to types, then some templates, some auto, some lambdas. The old vtables / RTTI approach I basically never use anymore.

Actually "C++ Crash Course: A Fast-Paced Introduction" by Josh Lospinoso seems to cover some good ground.
If msvc would support a more modern C, i predict a lot of people would use this instead of C++. (Thanks Herb)
C11 support is on the roadmap since a few weeks ago:

https://developercommunity.visualstudio.com/idea/387315/add-...

I hope this also means the MSVC team had a change of mind regarding this very unfortunate blog post which IMHO did more damage to C than anything else in the last 20 years:

https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an...

Your first link: that would be great, but somehow I can only find a statement that a c11 complient preprocessor is in the roadmap. Can you point me to something specific?
I can't sorry, since I'm not part of the MSVC team. The news that the MSVC preprocessor is C11 compliant made the round long before this specific ticket got the "Roadmap" tag slapped on though (which was on 20-Jul-2020). I guess we need to wait for the first results to show up in MSVC or a statement from MS.
And rightfully so, C code has no place in modern secure computing besides UNIX kernel clones, and legacy code.
(comment deleted)
Security should be provided by a sandbox technology. Is it wise to implement the sandbox in C (or C++, because that really doesn't make a difference)? Probably not. For most other use cases it's fine to use "unsafe languages".
Sandoxes don't prevent security exploits due to internal memory corruption of the sandbox.
But bad actors won't use memory-safe languages either ;) The purpose of the sandbox is to keep the damage contained, no matter if this damage was intended or not.
The less memory unsafe languages get used the better, regardless of sandboxing.

Here C++ has an edge over C, because it offers the language features for memory safe array and string manipulation, and most C++ compilers do offer bounds checking support, enabled by default in debug mode, and selectively in release if one so wishes.

Ideally, Swift, Rust, Ada, .NET Native would have replaced all use cases, but we are far from that ideal, so 2nd best solution, C++ for the time being.

Note that Apple and Google also reduce to the minimum the usage of C, and equally advocate C++ instead, alongside their managed languages for their OSes.

So yeah, you get C11 in the box, pity that the OS APIs are a mix of C++ and their own languages.

C++ as OS APIs (which so far only Microsoft seems to do in their UWP wrapper APIs, which is a fairly exotic use case) can be dealt with the same way as Objective-C on macOS and iOS: put all the code which talks to OS APIs into separate C++ or Obj-C source files, and put that code behind a simple C-API.

It's also interesting to note that Microsoft is only using header-only C++ wrappers, under the hood it's all plain old C-APIs via COM (because it would be a bad idea to expose C++ APIs in system DLLs).

The usage rules for C++ in Google's Fuchsia are so limited [1] that it is essentially a "C with classes", and it also has the rule that all shared libraries must have C APIs. I really don't see the advantage of using C++ for the underlying implementation compared to plain C if C++ has to be stripped down that much, and the public APIs are C APIs anyway.

[1] https://fuchsia.dev/fuchsia-src/development/languages/c-cpp/...

COM with C is just for masochists, and no UWP is not exotic, all new Windows APIs since Windows 8 are mostly UWP, with Win32 frozen in Windows XP, given that Vista basically rebooted Longhorn features as COM/.NET instead of pure .NET components.

Header only libraries are a stop-gap solution until modules are fully done, then good luck with those C bindings into .NET metadata used by UWP.

Regarding Android and Fuschia, C++ with classes is still better than plain old unsafe C and if you cannot see the safety that C++ brings into C, then one more reason why those companies are on the good path to remove C as an option.

Doesn't seem extremely limited at all:

- Exceptions, RTTI, thread_local, Statically constructed object all require runtime support and are problematic in a kernel so it is not surprising - Virtual inheritance: almost litterally nobody uses it. - initializer lists require static storage which is also problematic in a kernel - operator overloading and trailing return types are a stylistic choice, but at the end of the day they are a tiny bit of C++

Things that are allowed: actual OO classes inheritance (including multiple inheritance), virtual functions, RAII, templates (no restrictions at all), lambdas, all the recent goodies. I.e. all the things that make C++, well, C++.

So it is way less restricted than other guidelines I have seen for well known C++ projects.

There is one thing about Swift vs C++. Like C, Swift now has a stable ABI. C++ will never have a stable ABI. Better now to start abandoning C++ for better languages.
C never had a stable ABI to start with.

That is a misconception from developers that don't understand C ABI == OS ABI, on OSes that happen to be written in C.

There is no C ABI on IBM and Unisys mainframes, Android, ChromeOS, WebAssembly and plenty of other OSes written in other languages.

OS/2 SOM, Windows COM and UWP are ways to achieve a compromise regarding how to expose a C++ ABI in a language neutral way. And stuff like gRPC also allows for something similar with inProcess calls.

Many of those better languages depend on LLVM, so no C++ is not going nowhere for the foreseeable future.

Problem we had was language designers spent 15 years targeting the JVM for new languages. But now finally there are good native languages like Rust, Swift, Golang, etc. Next thing is to write full compilers in those languages and ditch C++ and LLVM.
Good luck getting Apple, Google, Microsoft, IBM, ARM, NVidia, Khronos, or industry standards like AUTOSAR to ditch C++.

In fact they seem more focused on bringing Rust like capabilities to C++ static analysers, than anything else.

JVM has always been native by the way, for those that bothered to get hold of commercial AOT compilers, like PTC, J/Rockit, Excelsior among many others.

on systems that use the Itanium ABI, the C++ ABI is as standard as the C one.
I abandoned Microsoft compilers a long time ago due to their lack of support for newer C standards. I know a lot of other people that did, too.

It may also have contributed to a lot of software developers moving to Linux, which has always had great C compilers.

Has anyone anything positive to say about C++, and more specifically C++20?

We all know the negative parts, any C++ related thread is always full of people repeating them over and over. What about some celebration time for now? A huge milestone for the language has been reached with C++20, can we share something positive about it for once?

Yes! The spaceship operator (three way comparison a la strcmp) is very welcome, and the no_unique_address attribute will be helpful for people who care a lot about optimization. Simplifications like these really help, and don't take a programming language genius to utilize.
As someone that really likes C++ templates (no other language seems to come close in power for such a compile-time typed system), I'm particularly looking forward to concepts, and I believe (correct me if I'm wrong) that they will make compiler errors for templated code much more straightforward, which will be a nice quality of life improvement even if not using concepts directly.
That strikes me as Stockholm Syndrome. No one in their right mind would consider C++ templates a good design for a meta-language. In fact the majority of older template patterns aren't based on good language design but hacks around conditional compiling via arrays of size -1 and crap like that.

A good meta programming language would be one that's as easy to program as a general language. lisp, nim, etc...

It's true the templates weren't designed as a meta language. C++ has a lot of baggage.

But, at least, you no longer have to iterate over arrays with size-1, (size-1)-1 etc these days. We have variadic template expansion, we have the (ugly, still not decent design, but useful) std::integer_sequence , and better still - we have pretty strong constexpr capabilities.

Such examples speak more to C++ templates as a mechanism for capturing usage patterns in a convenient form, thus effectively creating a special-purpose, domain-specific language, than they speak to such templates as a meta-language. "Meta" means "information about information", so a meta-language in this case would describe the mechanisms used to capture such patterns, not the patterns themselves.

I do meta every day, meta-meta often, and triple-meta occasionally. The rules language for my Expert System is a true meta-language, because I designed it to (among other things) specify the manipulation of computer languages. So its domain knowledge is about the nature of computer languages and how to automate their assessment / analysis, transformation / re-engineering, translation, and generation.

To give a real-life example, we used our Expert System to automate the translation of complex compiler front- and back-end code from a proprietary system language to C++ for a major computer manufacturer. The translation rules don't really care what the code is doing; they care how the code is doing it. The compiler team created new templates and classes to provide the functionality their system language had that C++ doesn't, and we adjusted our translation rules to ensure that the translated code invokes those templates and classes in a clear, effective, efficient, and readable way.

Exactly, old hacks and techniques. Thirty years ago, C++ template were limited and clever people struggled with their limitations, but now there are vastly simpler ways to do much more.
I think this is.. quite wrong. I don't think C++ is an amazing language (it's not in my top 3 personally, but I do work with it daily), but templates are one of the best things about the language IMO.

I have a lot of experience with many different types of metaprogramming (cl macros, Rust macros, template Haskell (and Typeable/Generic), ... even CLR code generation) and C++ templates are better than everything I've used other than Common Lisp once you really understand them. A really common C++ theme I see is people that don't understand things railing against them (I used to be in this camp myself, so I can identify with the sentiment).

Templates allow you to choose at will between nominal/structural subtyping (in a way), perform type-level logic, generate code that can be thread-safe or lock-free at the caller's whim... They are very powerful, much more than most devs realize, and if you understand C++, writing them is not difficult.

The "really understand them" part is, of course, the hard part. You need to understand the core language and the template language to be effective with them. I can see why even some experienced C++ developers shy away from templates.

Even if they're a good general design, half the uses of SFINAE are absolutely insane and from what I understand it's significantly harder than it should be to make a fully generic template across all kinds of edge case and corner case types.

The attitude with templates seems to be that if something is at all possible with hacks then there doesn't need to be any language support added, even if it would be vastly simpler to read and write and probably to compile. I don't think that works out well.

I wouldn't call myself a c++ expert but I have used the language for a long time. In my opinion, templates have a lot of awesome uses outside of SFINAE and if you find yourself reaching for SFINAE, that's probably code smell and you can probably simplify the design elsewhere to avoid it.

Generally I find the best use of templates is the most basic: you want to write some code that operates on duck-types. As long as one is able to control themselves and pick the right use cases for maintainability, templates are simple enough. In my experience, this is very doable.

Concepts are also a really cool way to rein in which types are accepted as a template parameter and have a lot of potential to make templates easier to understand and teach. To me, this is the most exciting c++20 feature.

With C++17, if constexpr removed most of the necessity for crazy SFINAE uses. Before that it was definitely worse. C++20 adds even more to make things more "semantic"; they're constantly adding better language support for templates.
No one disputes that meta programming is useful. What is disputed is C++ templates being a "good" way to meta program.

I certainly understand metaprogramming, but navigating very dense C++ templates is one of the most complicated things I've had to do in my life. One or two levels of abstraction and you will lose your ability to hold everything you need to solve a problem in your head, and after a few dozen lines the source code is unreadable.

> You need to understand the core language and the template language to be effective with them.

this is a bug.

I guess that just hasn't been my experience at all. I don't think a nested C++ template is any more complicated than a CL macro with a corresponding level of nested `.

I also don't really see how requiring understanding of a language to generate that language could be considered a bug - every macro system carries that requirement. C++ just happens to be (much) more complex than most languages (and I do agree that a large amount of that complexity is probably not necessary).

I'd argue it's significantly more complex because you don't have access to the C++ AST, templates are ultimately non-hygienic macros, their results are invisible to both developer and user, and potential errors are inscrutable. They're difficult to abstract over, and you will wind up repeating yourself quite often since you can't just write normal C++ code with C++ includes for helper functions and data structures.

I should be more clear about what I meant on the bug. C++ templates force you to understand the entirety of the language at once and hack around its edges because it doesn't support actual meta programming. It's hard for me to come up with a concrete example, but my experience writing some advanced compile-time evaluation with SFINAE patterns left me forgetting how things worked within minutes of typing them. Compare to say Rust, where the generics implementation is much cleaner and macro system better flushed out and easier to read/understand. Or the LISPs where your macro is just more LISP code.

And not for nothing, templates destroy compile times. They take a long time to write and edit and make everyone else using them work slower. All told, templates do not make it easier to write C++ except in trivial cases and first-order abstractions.

The kind of stuff you are able to do with entt (https://github.com/skypjack/entt#code-example) like `entities.view<Position, Sprite>.each([&](auto &pos, auto &vel) { ... });` is super awesome IMO. And then it compiles down to just directly inlined straight walks over the respective arrays (looking in godbolt.org). It's basically almost optimal for it.

I do agree that you can go insane with templates and have a bad time. You just have to choose well. However if you have a problem with there existing other problematic code in the same language (that may be separate from your code), then C++ is maybe not the best fit. There's a lot of C++ out there.

Any recommendation for books/blogs/videos/code to learn about this ?
> ... easy to program as a general language. lisp, nim, etc...

C++ templates are just a compile-time lazily-evaluated Lisp.

As always, the criticism of C++ comes down to "programming is hard, let's go shopping".

If you don't want to learn and you just want to do the bare minimum to keep your 8 hour coding job, there's already plenty of languages that nail this niche. C++ obviously is not for you, just move on and don't make a redundant comment.

What an asinine comment. I guess if you're real programmer you'll program everything in brainfuck. Isn't not hard to fathom that some language designs are easier to express and easier to understand than others and still get the same things done. C++'s meta programming via templates is clearly a hack and was never designed to do what it's being abused to do.
Other than lisp, which production ready languages do you think do it better?
I really liked camlp4 (an early fork of which is available as camlp5, but no longer a fundamental part of the OCaml ecosystem). I was able to use camlp4 to implement Erlang-style bitstrings, and they were as efficient as if you had written the most efficient code by hand.

https://people.redhat.com/~rjones/bitstring/html/Bitstring.h...

I consciously avoided C++ since the late 90s, lest its litany of accidental complexities crowd other more important things out of my brain. I was drawn into it recently by a work assignment, and have been pleasantly surprised by modern C++.

I find it much more pleasant to write, e.g., ODBC client code in C++ than in C, and templates have a lot to do with that. I'm not an expert with Lisp macros or other reportedly superior meta-languages, but I will say that when I write generic code in C# or Java, I really miss the power of C++ templates.

Template syntax is pretty awful, and accomplishing what I want can involve some really strange idioms, like SFINAE. The ergonomics are slowly improving with type deduction, constexpr, and now concepts.

As Stroustrup said to me years ago, “yes, I wanted a macro system but that word had already been colonized by the preprocessor, and we needed to avoid new keywords as much as possible if people were going to try it out.

Nowadays C++ and a powerful multi-paradigm programming language quite straightforward to use if you forget the word “C” in its name.

If would be a good instructional language if people didn’t fall into the lazy “a horse is a king of animal” OO trope.

> I believe (correct me if I'm wrong) that they will make compiler errors for templated code much more straightforward

Oh yes, that would really be awesome if that's the case. Wikipedia has a section regarding "Compiler diagnostics" when Concepts are used, the precision of the error message demonstrated is SO MUCH better than what you get with templates!

https://en.wikipedia.org/wiki/Concepts_(C%2B%2B)#Compiler_di...

Code example:

    std::list<int> l = {2, 1, 3};
    std::sort(l.begin(), l.end());

Example with templates:

    In instantiation of 'void 
    std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = std::_List_iterator<int>; _Compare = __gnu_cxx::__ops::_Iter_less_iter]':
    error: no match for 'operator-' (operand types are 'std::_List_iterator<int>' and 'std::_List_iterator<int>')
    std::__lg(__last - __first) * 2,
    ...
    ... // continues for 50+ lines

Example with concepts:

    error: cannot call function 'void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]'
    note:   concept 'RandomAccessIterator()' was not satisfied
Straightforward error messages are only an aspect of straightforward template definitions: the problem of restricting templates to suitable type parameters has the first general, explicit and well organized solution.
> no other language seems to come close in power for such a compile-time typed system

D is far more powerful, especially when you consider that it's had working constraints for (?) something like a decade now.

Simple example, try to express this in C++ without a windows full of syntax-soup (https://d.godbolt.org/z/Toc8ob), the template constraint is one line, and I can pass anything into a template using alias be that templates, a string etc.

Passing strings into a templates is a very common trick for generating code at compile time in the D standard library, although it wouldn't work in C++ due to how slow C++ can be to compile some times.

Sadly, D the language still needs to get their act together in what the language actually wants to be, and the eco-system suffers from this lack of direction.
If you use a tiny subset of C++, then you get a dialect of C with more type safety, namespaces, mostly-not-unsafe subtype polymorphism through class inheritance, and also okay parametric polymorphism through templates. That dialect will compile a bit slower (it's still C++ after all), but produce code which either has the same performance as C or is only slightly behind C.
Or often, faster than C, if you’re using compile time template expansion instead of runtime void* casts.
Yes, I have many positive things to say about C++.

It certainly has a lot of warts, but over the past decade, it has become easier and more straightforward to write code in various styles which used to be possible-but-a-pain (like functional programming), or not quite possible.

So with C++ you get performance + backwards compatibility + paradigm flexibility for the price of difficult, sometimes ambiguous syntax, some historical baggage you need to ignore, and slower compilation time. It's a decent tradeoff IMHO.

Specifically, regarding C++20:

* std::span is the best thing since sliced bread. How was this not in the library already? Cuh-razee... https://stackoverflow.com/q/45723819/1593077

* I'm happy that ranges support is inside the language. I can now `sort(my_container)` rather than the clunky `sort(my_container.begin(), my_container.end())` for example. And there are a bunch of useful lazily-evaluted range views. I only wish more of the ranges library could have been added. And I hope the compilation of ranges isn't too slow.

* Modules can now start replacing include files. Initially, this will only be a theoretical possibility, but within several years, no longer will your compiler have to deal with 100,000 lines of text or so per translation unit: It will be like in Java and other languages, where it's just your current file that needs to be compiled and the rest is already compiled. Of course the transition will not be smooth (feature macros, conditional compilation - not obvious to me how to replace them when using modules), but this is a good direction. We could see faster compilation times and content suggestions in IDEs.

* Expanded constexpr support means we can do more work once, at compile time, rather than repeating it at run-time (e.g. dynamic memory allocation - so you can have constexpr std::vector).

* Coroutines are something interesting which I am not familiar with (except the very rough general idea of different control flows being switched between. I can at least say it's interesting to look into.

* libfmt string formatting - Yes, yet another way to format strings: printf-style, iostreams, and now the "Python style", I guess you could say? It combines some benefits of both of the previous ones.

* std::source_location - you know how, if you're writing some error-handling function, you usually need to wrap it in a macro which gives you the filename and line number? Well, that's going away now. I know it's just a minor thing, but I hate having those macro'd error handlers.

* You can now tell the compiler to use a generated equality and comparison operators; this saves you boilerplate. Although in the C++ tradition, this capability is defined in a somewhat convoluted way under the hood.

Unfortunately ranges are only available in g++ at the moment. But I expect to have most of c++20 available in the next 6 months or so.
Pointer types in C can mean a bazillion different things, and C++ provides you with zero cost abstractions to unambiguously represent many of the useful ones (references vs owned pointers vs shared pointers vs arrays, off the top of my head), that alone makes it worth the price of admission for me.

RAII is a damned useful idiom too, makes writing safe code that much easier.

Tooling for C++ is pretty damn good in all the usual platforms

They are not zero-cost, but yes, it's good that they were added
unique_ptr isn’t 0-cost?
shared_ptr certainly isn't, last I looked at it there was some significant performance overhead since it's required to be thread safe.
Yes but imagine writing thread safe refcounted GC in C. It’s painful and easy to forget some of the handshaking.

Most of the abstractions (E.g. iterations) are zero cost as opposed to additional functionality like shared pointers or resizable vectors.

Whether shared_ptr are thread safe is an... interesting question. If you have to ask it the answer is “no”.

At any rate, the definition of “zero cost” isn’t “it’s the same as a raw pointer”. Rather, it should be read as “its cost is the same as the equivalent functionality rolled by hand”. Shared_ptr implements a ref counting mechanism, which, absent a real GC, is necessary for actual shared ownership.

> To satisfy thread safety requirements, the reference counters are typically incremented using an equivalent of std::atomic::fetch_add with std::memory_order_relaxed (decrementing requires stronger ordering to safely destroy the control block). [1]

That's why shared_ptr has horrible performance, the spec requires that the control block is thread-safe. Perf tanks due to the atomic load/stores. If you roll your own with a standard load/store you'll see significant performance increase which means it's definitely not zero-cost.

This is why Rust explicitly went with Arc/Rc[2] so you don't have to pay that cost(although ambiguous ownership I would argue is a pattern you should try to eliminate anyway).

[1] https://en.cppreference.com/w/cpp/memory/shared_ptr

[2] https://doc.rust-lang.org/std/rc/struct.Rc.html / https://doc.rust-lang.org/std/sync/struct.Arc.html

formally the answer to the question of "is shared pointer thread safe" is "no": modifying a shared pointer (for example by assigning to it) while another thread is reading (or writing) is UB (unless all accesses are done via the now deprecated std::atomic_* operations.

It is true that the ref count is kept atomically, which allows accessing two distinct shared pointers that happen to point to the same object from different threads. This is pretty much a requirement to support the baseline distinct object thread safety (aka "as safe as int), but it is not what the unqualified "thread safe" normally refers to.

/pedantic

Anyway, it is true that with shared_ptr sometimes you might end up paying for what you do not use, but doing otherwise would have made any use of shared_ptr in threaded applications extremely unsafe so it was felt that in this case the cost was worth it for a vocabulary type object.

> At any rate, the definition of “zero cost” isn’t “it’s the same as a raw pointer”. Rather, it should be read as “its cost is the same as the equivalent functionality rolled by hand”

What kind of definition is that? Zero cost is exactly that - 0 cost, the same performance as if you were not using the abstraction. The alternative to an abstraction is not "my hand-rolled implementation of said abstraction" - it is not using the abstraction, at all (but using lower-level mechanisms to achieve the same goal). 0-cost is used to tell people "you will still achieve the same performance by using the abstraction - and you gain additional benefits (safety, readability etc)". If I can get better performance with raw pointers, then smart pointers are not zero cost (it's still a good idea to use them instead of raw pointers! Just, let's stop pretending they are zero-cost)

https://gcc.godbolt.org/z/TMYso5

If you pass a unique_ptr it has to have redirection through a pointer, so it isn't quite zero cost.

However, since the entire point of using a smart pointer is to control the ownership I'm not that bothered.

What are you talking about? unique_ptr contains a pointer, that's it. Yes, to represent a pointer you have to contain a point. Passing it on or not makes zero difference and using a website that return unoptimized C++, is not a good place to gather intel. unique_ptr is zero cost, unless you use it across library boundaries without LTO.
Zero cost compared to a raw pointer. You are comparing apple and oranges if you compare it to a regular variable.

It has a null check on destructor (and a delete of course), which is good enough for "zero cost" to me

Hmm, now i thinked about this one but perhaps it is fair to compare unique_ptr to regular variables as well.

I guess it is more complicated than i thought, but i think it is fair to compare them pointers too. Because most of the time you will probably need to store it as a pointer

Being able to read is helpful. They are "zero cost abstractions". Yes, they are not zero cost, big surprise (I thought they wouldn't produce assembly instructions). A pointer is an indirect reference. But the abstraction around them is zero cost:

i.e. there is no way to end up with faster code that does the same thing, without using the abstraction.

This is the very definition of zero cost abstractions.

> Has anyone anything positive to say about C++

IMO, C++ has the following huge benefits.

1. Ambient performance. If you need a fast program and don't have a tight loop you can optimize, C++ makes ordinary behavior fast.

2. RAII is a very clean and understandable design paradigm.

3. The idiom of using "const" everywhere plus widespread copying of values makes "spooky action at a distance" way less common when doing OOP or imperative programming.

Looking forward to having access to coroutines. Also the <=> operator and ranges. Lots of really good stuff in this release.
I did C++ for 10 years before moving on to C# for the next 10. I had an opportunity to work on a modern C++ project for a couple years and took it so that I could learn the new stuff. The team lead was a big C++ fan and used all the latest features with compiler set to c++17 standard.

I could go on about the bad parts, but the good parts

1. lambdas

2. constexpr

3. threads

These additions did make C++ feel a little more modern.

It is a performant language that is relatively safe when you use safe practices. And quite mature with lots of library support
Plenty,

Finally we got modules, concepts will put an end to the fame of endless kilometres of error messages and compile time programming almost allows for static reflection.

I'd written C++ a bunch around 2006-2011 for gamedev, and jumped back into it recently and am really really loving it. I had a while in between of leaning into C which I think is important to do, to move away from the super OO based approach which I think C++ isn't necessarily about anymore.

Highlights for me:

- Type deduction -- basically using auto for variable declarations.

- Move semantics makes RAII actually usable since you can make heavy / important objects but then move them elsewhere and still have their lifetime be automatically managed. I use this in my game engine to wrap physics bodies etc. so that they are automatically removed from the scene when the component containing them is dropped (I'm using an ECS). A neat thing also is you can delete copy constructors and force certain types to be "move-only."

- Having been in C-land for a bit, I'm appreciating the ready availability of std::vector and std::string again. Also std::array is awesome.

- Lambdas are amazing. I often make simple control structure utilities in my modules that accept lambdas, and they are often inlined. I don't often do lambdas where I 'save them and call them later' -- they are mostly immediately called. This makes it safe to use reference captures.

As for C++20 I am mostly interested in seeing how it goes with modules Also the `requires` keyword will simplify some of my uses of `enable_if`.

A lot of the good stuff is also due to ecosystem and tooling vs. just language. My game works everywhere now: native macOS, Windows and iOS, but especially web due to Wasm! It also has an immediate mode API for rendering UI in Wasm, which I use along with some simple reflection to get an automatic entity inspector: https://m.imgur.com/dyUtL8f The entire gameplay code fits in like 700 lines: https://gist.github.com/nikki93/5893543a5e3d76a7858d54b74a4c... You can see how I don't do any pointer stuff or manual recource / memory management there at all.

Tbh in many cases with precompiled headers it almost feels like it builds about as fast as webpack. And then my "publish" is a simple rsync of static files to the server.

Another tooling / ecosystem thing lately has been godbolt.org which is wonderful for seeing immediately the asm that ur code generates. Which then makes you realize how good optimizing compilers for C++ are these days. I don't think other languages have come so far. And then with godbolt.org you can learn which constructs produce what code.

I'm using entt for the ECS: https://github.com/skypjack/entt you can see how it encourages the use of POD structs and non-OO code for the most part. It feels good to use C++ in that style as a C with the above features. I just basically don't use vtables / RTTI anymore. I do use templates a fair amount.

I do concede that this enthusiasm may have a lot to do with having had experience in C/C++ already for a while. If I was completely new to the language it'd be a lot harder. The backwards compatibility lets me keep all my experience (even if the point isn't to write exactly like how I wrote before, but to understand the motivation for the new features). I've also dug into Go, Rust, Nim, Common Lisp, Haskell, ... but weirdly modern C++ has been the best combination of ergonomics, control, and portability. Especially for Wasm you really just want deterministic resource management. I'd probably still combine it with Lua or JS for scripting eventually.

You do have to invest a lot of energy into learning the language and caring about the details, but I think C++ is very well positioned to reward you for that investment, and you are a...

Have been using it professionally for a little bit now. -RAII -Smart Pointers -Classes(or not, your choice) -Lambda Expressions -Amazing Standard Library -Lightning fast -A compiler that you can trust -Static types -Templates -Well defined semantics for pointers, references AND values. -Moving semantics.

And this is the "Vanilla" version of the features. In C++17 and C++20, there is all kinds of goodies like concepts and modules that I'm personally excited about.

Hate it all you want, but it's an amazing language.

I am mostly writing audio applications where I need maximum performance because the time budget is extremely limited (usually 1.45 ms to compute the whole audio graph). I'm working on Pure Data, which is written in C89, but my own projects are all C++. Things which make C++ much more pleasant than C:

* RAII

* lambdas

* templates

* function overloading

* operator overloading (used judiciously)

* inheritance and interfaces (used judiciously)

* an extensive standard library

* exceptions (depends on the project)

For me, the advantages of C++ over C are obvious and IMO there's no reason to use C except for legacy projects or platforms which don't have a C++ compiler.

Of course, C++ has lots of warts and things to complain about, but OP asked for the positive things :-)

Many of those features were already available in Turbo C++ for MS-DOS back in 1993, hence why I never liked C and only wrote straight C code when required to deliver projects in various contexts written in C.
This is another sad day for us, C++ programmers. Even more features have been added to the language that we didn't ask for and that are nearly impossible to learn and use in practice.
2020 gets worse and worse.
You don't speak for everyone, pipe down. Furthermore, nobody is forcing you to use these features.
What features weren't asked for as opposed to what was implemented that was asked for?
Great, now we just have to wait for about 7-8 years or so for all of these features to be widely adopted, and then we're good to go!
C++20 compiler support is already quite good among the main compilers (GCC, Clang, MSVC): https://en.cppreference.com/w/cpp/compiler_support
I'm talking about:

1. Adoption by users, including the larger, sluggish, corporate ones (and I'm being lenient with 8 years).

2. Transition from headers to modules.

> 2. Transition from headers to modules.

Yeah, this one is likely to take a while...

nope. I am using C++ 20 features in production already.
Even worse, all the devs jumping on using the C++20 features right now (like the other commentors in this thread) will make software that's near impossible to compile on a linux distro more than 4 years old. And even if someone compiles on a modern machine with a modern build toolchain there's no certainty that the binaries will run on the aforementioned slightly old distro.

C++xx new features and improvements are good. But they come very fast and that futureshock is causing the fever that is containerization "solutions".

I honestly cannot say if that's a GPT-3 comment or not. Are you implying that the 3 years cycle of the C++ committee is the reason why people are using containers? Without being disrespectful, that doesn't seem to make sense.
Not exclusively c++xx but more like the rapid pace of new features in all of the big libraries (glibc, etc). And it's not the only reason for containers but it's probably the largest.

I'm going to bet you haven't tried to use an older distro in the last decade and have kept up to date. Trying to run software from outside your repos that's written with the latest features is a serious problem on even mildly old distros. It wasn't such a serious problem with the slower rate of development 2000-2010. GCC 4 spanned an entire decade.

I get that on the big corporate server side there are different reasons for containers; for scaling, deployment, and all that jazz. But on the desktop, or in academia, it's the primary reason. It's futureshock and containers are the fever.

Actually, a compiler is one of the less problematic things to keep up-to-date, since compilers (at least C/C++ compilers) typically have few dependencies, and can live just fine "on the side" of the system's main compiler. But some libraries or apps need half the world and its mother to run, including packages with subtle clashes, and then you're in trouble.
The bigger problem is that you'll have to wait infinity years for people to use these features wisely. Neophiles will sprinkle them everywhere as though they're magic fairy dust. Luddites will avoid them forever. Very few will explore the space in between.
I'm looking forward to reflection and executors in 23. Then it will basically be the most powerful language. With compile-time reflection, you could add whatever language feature you want--almost as powerful as Common Lisp macros.
As someone who's only had C++98 experience in a code base that leaned more towards a Java style, are there some good guides or books on a more modern C++ style?
A Tour of C++ 2nd Edition, by Bjarne Stroustrup

https://www.stroustrup.com/tour2.html

> The ``tour'' is a quick (about 240 pages) tutorial overview of all of standard C++ (language and standard library) at a moderately high level for people who already know C++ or at least are experienced programmers. It covers C++17 plus a few likely features of C++20.

I will add that it's a good way to have an overview of modern C++, you can then go deeper on some topics with more specialized resources. It's a good read IMHO, with a good pace.

Thank you!
You're welcome :)

If at some point you're looking for more specific resources, I would suggest to ask on the C++ subreddit. I found people there to be helpful.

>"Even as a C++ programmer with too much spare time, it has become obvious that learning and using all of C++ is beyond impractical."

Who says on must know and use all the features of a language (especially the monster like C++) to write good code / software. Check what you really need for your particular task and be happy. I've found modern C++ a breeze to use as long as I do not pretend to be a language guru. Writing some sophisticated STL like libraries is highly specific and involved task and person/s doing that are not doing much of anything else so they would know all the of relevant C++. Using those libraries however is way way easier, the code looks pretty clear.

I use modern C++ to write various business servers. To me it is a single tool or two with clear and relatively easy subset of a powerful language. When I compare it with the monstrosity of some standard "modern" back-end stacks/toolsets C++ is starting to look like a small fish.

I don’t know why this was voted down. C++ has a lot of tools for library writers which are unnecessary when writing application code but make libraries more adaptable. Also c++ keeps a lot of backward compatible code so old code continues to run (so there’s less of the Python 2->3 anguish).

English is full of words I don’t use on a daily basis but that doesn’t make it bad.

(Not picking on python btw, just using a prominent example of an alternative path)

>"I don’t know why this was voted down"

I suspect it was not because of C++ but me mentioning a monstrosity of some modern back end stacks. I think people get attached to the way of doing things and it becomes akin to religion.

I'm actually actively learning modern c++ these days, and I like it so far.

On another note, Bjarne is 70 year old and he is still very active in c++ new features, very impressive. That gives me a hint that as a software engineer, I can be productive for many years to come as long as I keep studying.

I also hope Linus still maintains Linux kernel in the next 20 years.

Well, wasn't there any other more informative link than a tweet?
That’s a tweet from a committee member, just when the version had been approved. You can find a lot of resources in the other comment threads if you want to see more details.
I am reminded of this: https://www.devever.net/~hl/nexuses

"[...] because nobody programs in C++ — everyone programs in their own unique subset of the language. If you are told a program is written in C++, that leaves the following questions:

Does it use, or eschew, exceptions? Does it use, or eschew, C++ RTTI? Does it use operator overloading? Does it use, or eschew, the STL? Does it use, or eschew, C++11/C++14/etc. features? Does it use templates? Does it use virtual functions? Does it use multiple or virtual inheritance? Does it use static objects with constructors?"

isn't that great? nobody speaks English. we all speak our own subset of the language.
And yet people in cough some cough countries insist that their English is The English. Likewise, if we had and used a widespread definition of subsets of C++ it'd be pretty much okay. Haven't JavaScript gone this way ("good JavaScript")?
how much software in the world is written in C++, vs written in javascript, and how much of that is actually relevant, in that it contributes something meaningful to society?
Look at all the weak minded beta programmers complaining about C++ complexity, your weakness disgusts me.