Why I'm Choosing C++
cjdrake.com
cjdrake.com
Sometimes I like the "shiny new stuff" that is presented on the frontpage here. I take it for a spinn to see what I like about it and what I don't like about it.
But other times I just want to hack together something. Then I go and use the tools that I know. Imperative programming with Python, C++, JavaScript and C# with a sprinkle of functional ideas.
Why? Because it is about getting things done, and not learning the idioms of the new shiny stuff. You can try to convince me of the virtues of going with something less mainstream, but I have inertia... And some of you reading this have that too.
I occasionally see comments here with some reflections of "guilt" over that they don't use the new language/framework du jour. I don't feel "guilt" and not going to apologize that I use the tools that I use. This is how I've solved programmatic problems most of my life and I'm going to continue doing so. But it doesn't mean that I'm not trying to learn something else. Maybe someday I'll be doing functional programming with a language that automatically parallelizes my code, but right now I just can't shift my mindset to do it. I'm too busy building stuff with the tools at my disposal.
What changed for me was I learned HTML/CSS/JavaScript and in particular WebGL. Now I kind of get, upset may be too strong a word but, basically I can't stand not being able to share something easily. I see people making simple visual things in C++ or Python or GO and I'm like "why are you making me jump through hoops to see your creations? Why couldn't you just put it on the web so in one click I could see it and/or interact with it?"
I'm not saying there's no place for C/C++ or any of those other languages. I am saying though that if what you want to make is something interactive or visual (or audio) and you can do it in such a way that you can put it on the web PLEASE do that! C/C++ run it through emscripten. C# (well, if it's unity at least might be able to export to the web). I don't know of the Go->Web or Python->Web paths but mostly if it's not on the web I'm not likely to download and install an SDK just so I can check out your Go program.
If you're making an app or backend something fine, whatever, but if you're just making a visualization, a graph, a simple game for fun but not profit, please consider learning the tech that will lead to the least amount of friction for your audience. Most of the time that will be web.
What often isn't mentioned is that C++ has a much more diverse ecosystem than Rust. C++ has four major compilers, three major standard library implementations, and 30 years of associated tooling and library development. Occasional serious issues in GCC and libstdc++ (or Clang and libc++, or in Microsoft, ...) do crop up, and the ability to cross reference alternative toolchains is quite valuable. If Rust can hit enough critical mass the ecosystem will develop, but it isn't there, yet.
Yes, that is very true.
"tooling that can require a long and complex setup from an expert"
If one is on windows, one can 1. install visual studio community edition and 2. click "new project".
Sure, it's nowhere close to npm or Rusts's crates or go's dependency management but that's bit hyperbolic way to express it. I can waste hours trying to get Rusts' dependencies working if I'm using something bleeding edge.
Yes, this is the main reason I prefer visual studio :). I know my way around unixes but since I don't use them for my daily work I forget most of the things I would need to remember to be productive.
Contrast to apt-get install foo-dev or brew install foo on Linux and MacOS respectively.
Having a project that builds painlessly on third party developer machines requires effort from the project and is not guaranteed automatically by the chosen platform.
Apt-get also can fail if the dependency chain does not match exactly the configuration required by the project one wants to build.
The best way to build software on windows is different, perhaps even less elegant, but claiming that Linux/OS X builds are automatically correct does not match my experience.
Projects which have an incentive to provide a windows build usually can be built out of the box pretty painlessly, even with CMake.
From my experience, the best indicator of a pain free build on a platform is the number of users the project has on the said platform, not the platform.
I have spent a big part of my time trying to find that IDE developer experience back.
Nowadays Qt and KDevelop do a good job, but it wasn't always like that, specially in the mid-90's when we were already enjoying C++ Builder and Delphi on Windows.
Outside Windows, it's not so simple though. Most IDEs struggle with heavily templated code. For instance, I tried CLion for a while, but it completely runs into the ground when you use e.g. Armadillo (no completion, correct code is highlighted as incorrect).
Yes.
> Playstation
With a little effort, probably; the toolchains both use LLVM, and writing a custom target for Rust is possible. Someone managed to do it back in the dark times when Rust still depended on libuv [1]. I think that was before the "flexible target specification" [2] was a thing, too.
Whether Sony would allow you to distribute a game written in Rust is another question ;-)
> Xbox
Nope.
[1]: https://twitter.com/wickerwaka/status/479842553831776257 [2]: https://github.com/rust-lang/rfcs/blob/master/text/0131-targ...
> Yes.
Easily means using something like Visual Studio debuggers, with its graphical visualizers.
Command line gdb is something I use when there isn't any other option available.
Going by what was said above and how I developed in C++, it sounds like "easily" to me.
* breakpoint debugging * ability to step debugger line by line * high quality watch window
GDB does not qualify as easy. Ability to printf debug, while 100% mandatory, is also not easy.
Visual Studio support is mostly gated on LLVM support for PDB. We do have support for using the MSVC toolchain as of a couple of releases ago, so I'm not actually sure what if anything is left to get that working.
Also many thanks for the MSVC toolchain, that is what I have been using.
Examples:
http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-Everywher...
Unsurprisingly most of issues described below, boil down to Rust not being mature yet, and are perfectly fixable. However, fixing some of those will break backward compatibility one way or other and require effort that would be unnecessary otherwise.
Language is underspecified. In what order are subexpression evaluated in Rust? Unspecified yet, in fact it is even worse than that, it differs between borrow checkers (which I think uses the most useful one given Rust syntax: right to left behaviour), while code generation assumes left to right order. https://github.com/rust-lang/rust/issues/28160
What can you do with pointers in unsafe parts of code so that everything is still well-defined. There does not seem to be real answer to this question yet: https://github.com/rust-lang/rfcs/issues/1447
What does Rust guarantee with respect to lifetimes? In fact it guarantees much less than what would you expect. Take for example a drain method of a Vec. Drain gives you an iterator that moves elements out of a Vec. Naive implementation would leave Vec in a inconsistent state while drain iterator is still alive (because some of elements are already moved from), but restore Vec to a valid state in destructor of drain iterator. It appears to work because no one can touch Vec while drain iterators still holds mutable reference to it. Except it wouldn't work, because Rust does not guarantee that drain destructor will be executed, in fact in perfectly safe code it may not be executed at all. Surprisingly a borrow of a mutable reference may outlive the lifetime of a referent. At least it seems that Rust guarantees that those references would be inaccessible. https://internals.rust-lang.org/t/are-memory-leaks-considere...
There are quite a few language issues like this, and in general I found it very hard to find what exactly Rust semantics is.
Rust sends mixed signals about panic. On one hand it try to tells you that code that panics is probably badly broken, and may have left data structures in an inconsistent state, so you should not even try to access them. And Rust tries to ensure this to some degree by putting roadblocks on your way if you think otherwise (see Mutex poisoning, and strange things like AssertRecoverSafe you have to use when recovering from panics). Except in reality, all your desctructors already do access all those data structures. It seems that all those roadblocks are quite pointless.
Running out of memory aborts program. This is I think quite a bad decision (it seems that this may be a temporary one) for a language that have exceptions in form of panic. Not many programs need to handle out of memory situations, but handling those in programming language with exceptions and RAII is quite easy, and mostly boils down to: don't perform dynamic memory allocation in destructors. This is a step backwards from C++.
Bugs, bugs and more bugs. Rust not calling your desctructor for variables in the same scope after panic, still there after more than a year: https://github.com/rust-lang/rust/issues/14875
Borrow checker is interesting, certainly prevents you from writing buggy code, but also prevents you from writing code which is perfectly fine. In certainly does not play nice with ideas which are very common in C++ world, any STL algorithm + container would be a good example. I am still not sure if it is worth the effort, it seems to prevent problems that I don't commit in C++ anyway.
Immature state of ecosystem, libraries, documentation, ... .
In general you probably will not be as productive in Rust now as you would be in other languages. If you are interested in developing those libraries that are currently lacking, having some impact in how Rust language may look in a future, then Rust community is certainly great. But a lot of people have different priorities.
We aren't changing anything you're talking about, except for bugs.
> In what order are subexpression evaluated in Rust? Unspecified yet, in fact it is even worse than that, it differs between borrow checkers (which I think uses the most useful one given Rust syntax: right to left behaviour), while code generation assumes left to right order. https://github.com/rust-lang/rust/issues/28160
That is not the standard question of right-to-left vs. left-to-right argument order. That is perfectly well defined: left to right. Rather, it's a very subtle question involving code nobody would write in practice.
> Except it wouldn't work, because Rust does not guarantee that drain destructor will be executed, in fact in perfectly safe code it may not be executed at all.
This is never a problem in real world code. The leakpocalypse affects nothing in the real world and was a lot of debate over what amounted to a very minor hole.
C++ has no guarantees about destructors being executed at all, and frequently due to memory management errors they aren't. Rust guarantees that they'll be executed unless you're leaking.
> Bugs, bugs and more bugs. Rust not calling your desctructor for variables in the same scope after panic, still there after more than a year: https://github.com/rust-lang/rust/issues/14875
C compilers have miscompilations too, with the same frequency. I never hit these in practice.
> I am still not sure if it is worth the effort, it seems to prevent problems that I don't commit in C++ anyway.
Yes, you do make those errors. Empirically. All large C++ projects I have ever seen have memory management errors, unless they're doing hugely expensive verification. I have not yet seen an exception.
> Running out of memory aborts program. This is I think quite a bad decision (it seems that this may be a temporary one) for a language that have exceptions in form of panic.
It's not a temporary one. Most programs don't need to handle out-of-memory conditions, and having the language do this is not a step back from C++. For programs that do, you can use libcore (recently stabilized!) and handle this yourself.
You're looking through the issue tracker, pulling out random bugs, and overstating their impact. Someone could do the same to any C++ compiler; LLVM has horrible-looking miscompilations all the time, and it's still production ready. Of the reasons not to use Rust, miscompilations (which is the vast majority of what you're talking about) aren't anywhere near the top of the list; they occur more or less with the same frequency they occur in C++. You can't complain that the borrow checker doesn't solve memory management issues you hit in C++ and then simultaneously criticize Rust by citing a whole bunch of issues that occur with much less frequency than those memory management issues.
[1] http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines....
Having a strong foundation in classic languages and an ability to adapt to modern paradigms seems way easier than the reverse.
For instance at a low level, machine to machine communication, C over the internet, Node APIs, etc shouldn't matter to getting things done...
API and functionality can be decoupled, but you will still need to have someone available to understand the path from A to Z
This is exactly why people avoid C++. More features != better language.
Many others are in form of libraries, and the C++ standard library is quite anemic compared to e.g. C# and Java.
Apples, oranges, etc.
Rust isn't there yet and when opting for a longterm project you want stability, access to experienced developers and good time-tested libraries. I love the idea of Rust but I'd still not consider it for use-cases we use C++ in for at least a few years still.
For some reason people seem to forget there are still programmers for whom the only platform they need support for is not just the deployment server.
Non-embedded platforms. Many embedded systems only officially support C.
More features != bad language
as long as you have a choice in the matter.
However, a lack of features can definitely hurt if you need them.
Maybe more features != bad language per se, but they definitely add cognitive cost to the language and this is bad if the cost is greater than the benefit. In the case of C++ I think they have gone overboard long ago.
C++ does change too much, language (specifically in this level,python is okay to change) aren't suppose to be stable as much as possible ? every 2,3 year they literally add new language to existing C++.
What decision should existing library take? rewriting whole library? rewriting critical part ? in these case almost all of developers time should be devoted on rewriting existing C++ code.
look at C. They don't add shitpile of feature to the standard every 2,3 years.The may fix some criteria.But it does not even count in compare with what C++ committee doing.
p.s. one of my friends in college used to joke about C++. He calls C++ : "feature adding contest".
Why on earth would you rewrite existing code just because the language gains new features? Old code is not going to magically decompose - that's one of the benefits of C++ - you can continue to use the old battletested codebases while utilizing the nice features of C++11 and onwards.
"p.s. one of my friends in college used to joke about C++. He calls C++ : "feature adding contest"."
Adding the capability to utilize more degrees of freedom into a system does not mean one is compulsed to use all of those. One of the pitfalls of C++ is that people imagine they must write "idiomatic" C++ - which they understand is that they must use every language feature available. Which is idiotic. The only good C++ is pragmatic C++ - which depends on the problem one is going to solve.
not sure if that will happen, but it might
Well, before people were complaining that C++ didn't change enough. The core language did not really change from 1998 to 2011 and that was showing. That said, I cannot really see what the complaint is about, since you can still program in C++ as if it's C++98 or C++03.
(I share most common critiques of C++ and think Rust is probably its replacement. However, it's a fact of life that there are major C++ codebases out in the wild and there will be for the next 50 or 100 years. So, it makes sense to evolve the language for such projects.)
Mostly people who didn't use it.
I wish Java had auto type (the idea I believe Java people omitted for several reasons).
I also think the C++ community is really great - and this reason alone is able to give this platform a promising (than for many others) future. The youtube conference videos are awesome and I learned quite a bit from these lads (even doing Java full time).
A lot of the cool stuff being integrated in modern C++ has been present in D for ages ('enum class', 'string_view', 'constexpr', 'auto', ...) ... D has a real module system (=it compiles fast) and an extremely powerfull template system. It's one of the rare languages allowing introspection (e.g you can statically loop over a struct members) without bringing in "dynamic" stuff (e.g add members at runtime, etc.).
For at least some problems people will not want to use a GC, and D's story there isn't as good as Rust's.
However, the garbage collection in D turns out not to be an issue in practice. In D, you do have destructors and deterministic deallocation when you want to (in one word: RAII).
Eh. Often the whole "ownership" thing is irrelevant. For a lot of high-level programs, trying to express things in a Rust-ish "ownership" style with pointers adds a lot of syntactic and semantic overhead.
I don't see how it can ever be irrelevant, unless you use immutable data structures everywhere. Does your class/struct provide getters? Ownership! You have to think about what you return. When you are not careful, the calling code can break invariants of the data structure. Consider the following Go code:
type Foo struct {
sortedSlice []Bar
// ....
}
func (f *Foo) sorted() []Bar {
return f.sortSlice // Outside world can break invariants.
}
Now the outside world has access to internal state and can break invariants (make sortedSlice unsorted). You have to decide to: make a copy (and waste time) or document this fact (and put the burden on the user of Foo). Suddenly, knowing from the signature what the ownership is and having the compiler fail on violations, looks pretty useful!Tony Hoare once called the null pointer his one billion dollar mistake. I think the lack of ownership semantics (or immutability) is an even bigger mistake. Some of the most difficult and aggravating bugs that I encountered (even in relatively simple web services) were caused by (a lack of understanding of) ownership. Throw in some concurrency and you have bugs that occur frequently, but are terribly hard to reproduce consistently.
How does that avoid race conditions? What happens if I quickly move my pointer around? i.e. b=a;a=null;c=b;b=null;d=c... etc
Garbage collection trades the problems gc brings with less program complexity and programmer time. It's a degree of freedom that one can choose (if one can choose the language one uses).
"Reserve memory for this entity when I declare it and release it when I don't seem to be using anymore" is huge leap in getting computers to assist us in our tasks. But sure, there are lot of problems domains where this is not a good thing.
Now you can build systems that detect cycles who lack ownership outside of the cycle and break them. We call those systems garbage collectors.
GC is indeed a hack: it approximates an infinite memory system on systems that have finite memory. Reference counting is a worse hack: it approximates a GC on languages/systems that can't afford a real GC.
And I say this as a C++ programmer that has written very little code on GC'd languages.
We're working at making it much better. Recently added, for example, is the ability to catch exceptions thrown by C++ code.
I'm not sure why this is, as D would seem a perfect fit for writing stuff for the Raspberry Pi and similar; the other usual suspects have focused on ARM support almost from day 1.
Lending a hand there it's been near the top of the list of "things I'd like to do if I had some spare time" for a long time, but I haven't come around that yet. It looks like a fun project, and not one you come across often. Want to write "Helped port a major programming language to ARM" on your resumé? Hurry up!
I'm afraid Java spoiled me with GC, cross-platform libraries (especially the concurrency API, Joda-Time, Joda-Money, etc), JUnit, SCM (build, dependency management by Maven), great cross-platform IDEs that I'm really having hard time dragging my feet to C++.
Should I start with C++14 and skipped anything before that?
Any tips in how to deal with dependency-management and build in general?
What about unit-testing framework and some best practices?
For a cross-platform GUI library to develop Desktop applications I recommend wxWidgets or Qt. I prefer wxWidgets myself. To build GUI, I recommend wxFormBuilder.
For games, well, there's a lot to choose from. It depends on what kind of games you want to make.
Yes! C++14 is a much better language than C++98 and you can be perfectly happy without most of the ugly details. Stick to the new nice ways of doing things and forget (mostly) about the old.
A random collection of anecdotal stuff and opinions that comes to my head:
For common utilities for game development stb libraries are fantastic: https://github.com/nothings/stb
For general idea how to structure code you could google "data oriented design c++".
Try not to structure your solution around class hierarchies but prefer data pipelines.
Write your code so that it's easy to debug.
Prefer to structure your solutions around stl containers and stl algorithms.
Avoid using inheritance as long as it does not reduce code complexity. If you use inheritance prefer to use only abstract base classes. Do not use template metaprogramming unless you are absolutely sure it's the most simple way to solve your problem. Avoid multiple inheritance like the plague. Ignore my advice if your problem is such that they don't make sense.
Try not to solve any other problem than the one you have immediately in front of you, and solve it as fast and simply as possible. Do not try to create some "framework" to solve your problems but prefer simple code. Refactor your code as your program progresses. This point might be obvious - but for me personally has been the most difficult thing to learn - writing agressively simple code is the best thing I've learned. This does not mean that the abstractions that are implemented are necessarily simple - just that the implementation is as easy to read, easy to debug and easy to reason about it's dependencies, as possible.
If you can trade off complexity of dependency with a little bit more code, prefer little bit more code. I.e. if you have an itch to include a library because you need a single function, think hard about implementing or copy pasting the function to your codebase. Once you are confident enough that you know you need something, only then include it.
Learn some OCaml :) - really, I feel like much better C++ programmer after I understood how a properly designed language with a static type system works. (I hear "Real world OCaml" is a good book).
This.
Or F#.
This is definitely a niche compared to normal web development though. A lot of what I like is what's already been mentioned: the mature ecosystem. I'm sure the new contenders will mature over time. I'm really looking forward to using rust. I can't justify learning it yet though ;/
In cpp17 we get couroutines. Its like await in c# only more general and powerful. In cpp20 we will get parallel executors. Kindof like cppamp and openmp only more general and powerful. It will bring supercomputing mainstream.
Its exciting times for cpp. There are already some experimental implementations to try out. There are also a bunch of other big features coming out. Modules, concepts, transactional memory, compile time reflection, ranges, views, etc.
People can hate on cpp all they want. I'm super excited, and think they are missing out on the future.
The claim that parallel executors bring supercomputing mainstream is puzzling to me, because OpenCL has been around for a long time, is more widely supported, and is far easier to run on e.g. GPUs than the full C++ language.
I turn to reddit for substantive C++ discussions.
EDIT: fwiw, I've found the actual cpp community to be a delight.
People here have cited specific problems with C++ over and over. There are legitimate criticisms of the language that aren't "inane".
Personally, my biggest issue is that it's not memory safe, which leads to people making the same memory management mistakes we've been making since the '70s. At the same time, attackers have seen ways to weaponize use after free in ways that were not thought of when C++ was designed—and C++'s vtables make it much easier to do so. RAII and smart pointers have not proven to be an effective way to mitigate this, as a trip to any Web browser's bug tracker will demonstrate.
I do not believe this specific problem can be effectively fixed in C++, even with the ISO Core C++ lifetime checker, for reasons that I've elaborated on at length before.
Please don't misquote me. I did not say criticisms of C++ were inane. Obviously there are many legitimate criticisms.
What I said was the reason people get so upset about C++ must be inane. IMO there's no good reason for an adult to get upset over a programming language.
Having said that, C++ really, really needs to start throwing out its bad ideas and creating sane defaults that mercilessly break backward-compatibility. This applies throughout the standard library and the language. It can be done in phases (e.g. identify bad behavior; introduce an opt-in compiler mode per file to change defaults and not allow the bad practices; wait a few years and change the default; wait a few more years and remove the old mode forever). C++ also really ought to provide a standard way to partition unsafe behavior from safe behavior; the vast majority of programs do not need the crazy things that are possible in C++, and it shouldn't be a big deal to require extra keywords or compiler modes to enable dangerous language features.
I'm not really sure this is going to be feasible, assuming by safe you mean memory-safe like most other languages. The ISO Core C++ lifetime profile is a very interesting attempt, and I hope it works out, but there are serious issues I see around shared_ptr and aliasing that lead me to doubt how much use it'll get.
Quite a few hash tables out there, and very complete standard-library-like utility libraries too. (aside: failure to use one of these is a major cause of bad, bug-ridden C code, containing for example calls to dangerous old-school string API from the standard library. If your C is of any size and you don't have a good string abstraction you are doing it wrong.)
There are lots of circumstances where I'd use something besides C, for sure. But if I was using C for a good reason, and needed a hash table, in most cases I would not write my own.
Most popular programming languages nowadays are providing fancy runtime features (GC, introspection and reflection, dynamic dispatch) at the expense of performance and unpredictable operation. You may get some control over the execution semantics, but not much. For most use cases, I suppose this is fine, but when you go deeper or higher(in the Y performance and scalability axis), you start to question your choice and realize you don’t know what is really going on, especially if the profilers tell you that the culprit is the language runtime, and so you end up spending your time working around the language limitations instead of doing ‘real’ work.
The prevailing opinion nowadays is that C++ is complex, and use of templates, operation overloading, and even hierarchical objects structure, makes it hard to understand what is going on. It certainly mystifies many ‘pure C’ developers who are eager to come out and speak against the language, as if they are on some sort of mission to bash it, or just because they are not familiar with the language themselves and, well, if other like minded people are speaking against it, they may as well join them.
C++ is is a superset of C, and everything availed by C++ is optional — you absolutely don’t need to use anything you don’t want to use, or don’t feel yet comfortable using. I don’t understand why this just escapes more people who speak against it. Maybe because it’s not helping their cause, whatever it is.
There are brilliant people who will work around the limitations of a language and deliver incredible products, frameworks, libraries (Aeron - https://github.com/real-logic/Aeron comes to mind). There are languages that are better suited to many tasks than C++ - where performance is a big concern, but managed runtime environments and writing high level code makes more sense (or maybe you just care about compilation times, a very valid concern). There is no perfect programming language.
There is only the language that works best for you and your needs. For me, that is C++, and I can’t wait for the C++17 updates.
After several tutorials, text books, learning the new features in C++ 11 etc, my mind has changed. C++ is a horrible language trying to get better. Beyond the usual crap and total disregard of good design that this language and its libraries exhibit , it does not fail to suprise me something like fstream.good() to detect that the file has not reach its end , its just blows the mind.
But C++ is a necessary evil in my case, so the torture continues.
On my case, if the language is not part of the SDK, usually it no use discussing its use with the customers.
At least C++ is way safer than C, if one cares to use its features.
Thats the issue with offering an alternative to C++, its not enough to offer a better design language you also need to replace countless of C++ libraries that very capable , mature and very well established. Hence why there is no true C++ replacement out there beyond Java.
Delphi was awesome in countless diffirent ways but just lacked the library support to make it as popular. But at the time was as popular as python is nowdays with around 1 million developers and Borland C++ had 2 million. However at the same time VB had around 6 million and Visual C++ much more than that.
C++ is way safer than C but also way more complex. Which comes as no surprise why C is the go to choice for small libraries. Frankly I rather go C++ as well.
So where we get to use to still use C++?
Interfacing with hardware, COM libraries, JVM/CLR agents and lately portable native code across mobile OSes.
Someday using Rust, D, Go, Swift will be an welcome option, but they aren't there yet, at least for the type of customers we work with.
True that.
I really want to know how it determines whether a page is suitable for reader mode or not (but I can't find any documentation on that). Even on my blog, it allows reader mode on the "about" page, yet not on any of the actual articles, despite them being structured very similarly. :/
I became something of a C++ expert for the next 20 years. I turned down a job in 1994 because it was in Objective-C and I perceived limited future.
Later, wishing to build iOS apps, I re-encountered Objective-C. I guess I had the choice to write substantially in C++, but Objective-C is good enough for most app stuff and I never bothered.