Real-world C++ is an array of sometimes mututally-exclusive dialects, patterns, rules, sub-dialects.
Reading MFC is nothing like reading Qt which is nothing like WxWidgets which is nothing like Boost which is something (but not quite like) the STL which is way different from Apache C++ libs which is way different from what Google's C++ libraries are...
This is what happens when a language is "un-opinionated", throws everything including the kitchen sink at the language, tries to compile C and legacy C++ while introducing new features oh and also can't break existing code.
It's on its way out, no doubt about it. And we'll be better off as an industry for it, I'm sure of it.
Rust, Go, and others will be there to fill in the gap in a much better, saner, safer, maintainable way.
MFC was the vilest, most horrible abuse of C++ from the day it was released. Anything that involves MFC should just be rewritten with C# or turned into a webapp. I wouldn't take a job that involved programming MFC.
And of course, if you admit that exceptions aren't worth worrying about, then you'll start to question the entire "C++ way," which usually ends in disillusionment.
Alternatively, instead of disillusionment, you may still kind of enjoy C++. But suddenly you find that it's been three years since you've worked with C++, and on reflection, you haven't really been missing out on much of anything at all by not using C++.
It doesn't seem like C++ solves the right problems, even with the new dialects. Programming languages should be convenient to think in. By immersing yourself in the C++ mental model, it becomes difficult to keep a large-scale architecture entirely in your head.
In my experience, this is literally backwards. RAII is the only way to make exception-safe classes that aren't a gigantic mess.
> It doesn't seem like C++ solves the right problems, even with the new dialects. Programming languages should be convenient to think in.
No, some progrmaming languages should be convenient to think in. Some need to be uncompromisingly fast. C++ is in the latter set and nothing more convenient to think in is faster.
Yes, and C++11/14 make significant strides toward being more convenient to think in as well, without compromising speed. In fact some improvements also improve speed in some cases.
I wouldn't call Herb Sutter's _Exceptional C++_ a huge tome and it seems to be the standard treatment of exception safety.
I'm not saying it's impossible to write exception safe code. I'm saying that you can write code without exceptions without being worse off for it.
So I'm curious about why you think RAII makes writing exception-safe code difficult?
The book is excellent. For anyone who wants to use C++ exceptions, it should be required reading. But as someone who has gone through that gauntlet, I feel that I probably would've been better served by spending my time on something other than mastering the finer points of exceptions.
The reason I started talking about C++ exceptions in the first place is because, in my experience, when someone is very pro-RAII (like the original commenter I responded to), they also tend to be pro-exceptions. This isn't always true, but on average, it seems like either people prefer both or prefer neither.
Writing exception-safe code is certainly one of the hardest challenges available in C++, so if you enjoy a good challenge, then it's hard to do better. But if you're just looking to design large-scale systems, it seems like exceptions are unnecessary, as Google has demonstrated by banning the use of exceptions in their codebases.
In my experience, by refraining from using exceptions, it's possible to design large codebases more quickly, with fewer bugs, and without losing any safety or extensibility. However, this is simply my personal experience, and it may be mistaken to generalize this into a claim that all codebases among all C++ teams should refrain from using exceptions.
So, that's all I meant. I was also in excruciating pain yesterday due to a certain tooth that decided to segfault in my mouth, which may have contributed to the adversarial nature of my writing style. I feel bad about how I came across, and I sincerely apologize for it. No excuses, though: I should've done better.
exceptions (specifically, exceptions from constructors) are part of what RAII is, so it's only natural that people "prefer both".
As another personal anecdote, in my experience working with a large (175MLoC at last count) mostly-C++ codebase, I can't imagine how painful it would have been if the code didn't use exceptions.
I can't understand how a correct init method could be easier to write than a ctor, given that the compiler is required to generate code that knows which of your base classes and fields are already initialized at any point they could fail, which you would have to do yourself after moving to an init method, as well as losing the guarantee you can't silently ignore an error by forgetting to check for it.
"That's why C++ is overly cumbersome unless you ignore most of its capabilities, like exceptions."
Complete non sequitur. Exceptions are not "most of C++ capabilities". In fact, you can refuse to catch or throw exceptions for 99% of your (millions of lines) of code and still end up with a very large, stable code base running a large portion of the internet. Ask Google.
Today, there's pretty much no viable alternative to C++ for writing large scale, high performance systems with reliable performance guarantees. You could do it in C if you have a religious anti-C++ agenda but that would be like cutting off your nose to spite your face, and you'll end up in a horrible mish-mash of macros and generated code all over the place for a project with any level of complexity. Rust or D might get there some day if they manage to attract a solid community and big corporate backing. But they are certainly not there yet.
The point is that these features are infectious. If you don't want to throw exceptions, how do you handle a failure in a constructor? And then if you abandon constructors, other C++ features are unusable without them. And so on.
To add to this point: There are C++ frameworks such as Qt who don't use exceptions at all! And what impressed most: When writing a Qt application, you don't even miss exceptions. You don't have to resort to C-style return value checking all over your code. How is that? It took me some time to figure this out, but I believe it is because Qt applies the "Null Object" pattern consequently - down to the deepest depth of their framework,
Have a look at Tarsnap's source code.
True on my case, now using the language mainly on hobby projects, although we are very good friends since 1993.
Personally I would like safer systems programming languages from Mesa branch of languages had more use in the industry, but OS vendors decided to embrace C instead, and we ended up in the exploits everywhere that we enjoy nowadays.
C++ is not perfect, but it surely is way better than C in terms of safety.
Until a big OS vendor decides to push another systems programming language, we won't see any major adoption from the alternatives.
RAII has been with C++ almost from the beginning.
MFC's greatest benefit was that it made returning to plain win32 C programming without MFC a pleasurable experience.
Microsoft team made a prototype OO framework even more OO that what OWL and others offered. MFC was the result from the feedback over the said framework.
I'm also not convinced that Rust or Go are better or saner.
Maybe Rust will offer such stability in the future. But that's of no use to people and organizations who need to develop software today, and who need to be able to trust that the code they write now will compile and work tomorrow, a month from now, a year from now, and perhaps even decades from now.
C++ does offer stable, standardized, well-supported versions of the language. C++ does offer stable, standardized, well-supported standard libraries. There are numerous high-quality free and commercial C++ implementations available, for just about every platform imaginable. It provides a robust and predictable platform that serious and massive software systems can be built upon.
The theoretical benefits that Rust may bring are pretty much irrelevant as long as it isn't a production-ready language in the way that C++ is.
Not that I am disagreeing with your points, I am not. However, when people talk about C++'s problems, I immediately assume they talk about C++'s problems as a language rather than it's ecosysem.
Rust isn't out there to tackle C++'s ecosystem, tooling, legacy code or professional workforce, but rather Rust aims somewhere near C++ and fixes many of the language flaws which are inherent in C and C++, while still being competitive in performance and low-level control.
Rust is a pretty cool language, but I can't help being reminded about another very well-designed but ultimately unsuccessful C++ challenger, D. The parallels are really hard to ignore.
D, like Rust, had great syntax and was a breath of fresh air after coding with C++98. Neither Rust not D has a sponsor with really deep pockets to encourage adoption. Neither came out of a standards process. Both have had compiler and standard library issues. The big difference between the two at this point seems to be momentum and where the two are in their parabolic trajectories.
Also, Mozilla has much deeper pockets than Digital Mars.
Still I agree with you that it is very likely that Rust will follow a parabolic trajectory. The advantages as perceived by the industry compared with C++11/14 will be too few. At the same time it does not have the ecosystem.
Go succeeded because of Google's deep pockets and, perhaps more importantly, because it filled a large niche that even the authors did not anticipate: a faster language for Python and Ruby aficionados.
The problem is how to move OS vendors away from C's influence.
Rust is memory- and type-safe (as in: the compiler will not let you write a dangling reference, invalidate an iterator, or write exception-unsafe code without opting into an unsafe dialect). The security benefits alone of that are enough to justify the language for our use cases, and, from what we've seen, for many others. Safe zero-cost abstractions are a niche to its own.
What you describe is very different from, say, how Sun pushed Java, or Microsoft pushed C#, or how Apple will likely push Swift, or how a huge portion of the entire software industry pushed C and C++.
Facebook's Hack language is probably a much better example than D is of a language that they're actively supporting. It's a creation of theirs, rather than just a creation of somebody else's that they find useful in some limited cases.
Try watching new projects pop up at Rust CI [0] for a few days. With the possible exception of Node (which is not even a PL), I've never seen a language ecosystem grow this vast, and I'm a PL afficionado.
I think in a year's time, the question of Rust's stability and ecosystem will be entirely moot. It's a tough wait meanwhile, but I'm still investing the time in learning Rust (and it's a significant investment).
When I last looked at it, probably 40% to 50% of the projects listed had builds that were in the "failing" or "error" statuses.
That indicates that one or more of at least a few things are happening:
1. The Rust language and its standard libraries are changing at a pace that results in previously-compiling code needing to be modified before it will compile again with a newer version of the language/implementation, perhaps a very short time after the code was initially written.
2. The Rust compiler or other tooling is crashing or failing in some way while compiling these projects.
3. The projects themselves aren't being maintained on an ongoing basis.
4. The projects themselves were never building properly in the first place.
5. The projects' developers are targeting different versions of Rust (which probably means there will be interoperability problems for anyone trying to use them in a larger projects, especially when it comes to libraries).
And while there may be a lot of these projects, I've never found the quality to be very good. Many of them are extremely limited or incomplete. Many of them are little more than casual experimentation. Many of them are only developed by a single person, who often has appeared to have lost interest.
Those factors are disconcerting, especially for somebody who wants to use Rust for serious product development. It does no good if there are hundreds of libraries available for use, but half of them don't even build, and the ones that do are very incomplete.
Yes, I completely agree, and this is an entirely normal part of the language ecosystem development cycle. Rust is at the tail end of the experimentation stage, and as it converges on 1.0, more people will undertake serious projects.
I'm not at all worried about the quality of Rust projects. I'm just happy to see so much enthusiasm. I have no doubt that all this enthusiasm will transfer into some powerful libraries as Rust continues to stabilize and reaches 1.0.
But yes, it's still to early to use Rust for production unless you're willing and able to write your own libraries.
Then again, the "batteries included" approach of Rust's standard library leaves not much to be desired outside of domain-specific libraries.
People complain about the GC being available to use while simultaneously complaining that to avoid it you have to manage your memory yourself. You can't have it both ways. There is no memory allocation strategy that works best in every situation. Sometimes ref counting is best, sometimes stack allocation, sometimes RAII, sometimes memory pools, sometimes its the GC.
Rust has done some cool work with memory but even it doesn't free the programmer from having to consider and choose which memory allocation/ownership option is going to deliver the best performance on a case-by-case basis.
You're right about Rust and Go having much deeper pockets. D isn't backed by any corporation. It's 100% a community project. Maybe it won't ever gain a significant market share because of this. I don't know.
What are the compiler/standard library issues with Rust? Sure, it's taken time to get to a high level of quality, but no language compiler and library is going to spring out of thin air fully complete. In particular, I'm confident that the Rust compiler is of high quality for its age, especially in the quality of the generated code.
I'd like to concur. I've used the Rust 0.10 compiler and the only bug I encountered was that generating debug binaries was somehow broken. Apart from that, it was one of the smoothest experiences ever and the error messages are amazing.
In the C world this is extremely arduous since need to bubble the allocation-failure down through every level of code, adding cleanup to just about every function call. If you're using C++ and RAII you can just catch std::exception in one place to cover a huge number of places that an allocation can fail.
In modern systems I'm familiar with, malloc only reports failure on bogus inputs like -1, or address space exhaustion. Your process is likely to be killed before exhausting your address space (think iOS OOM handling, or Linux overcommit), especially on 64 bit. So checking for allocation success just isn't that useful any more.
The first is process limits.
The second is exhausting kernel data structure space for things like page mappings. I've seen this recently in AIX when allocating lots of memory that alternates mprotect permissions.
Even in the absence of the OOM killer (i.e. the old days) you had to do this -- otherwise the machine might be swapping itself unresponsive for ages before you ever get malloc()==NULL
Gotta love putting forth every effort in software to keep the BOM down :)
Are you talking about enabling exceptions, or throwing them?
I don't think it's very popular today. Modern implementation don't use this anymore and do not incur run-time overhead when no exception are thrown. However, they do incur some space overhead: the implementation need to maintain pretty large tables to know what needs to be unwound (which destructors to call, in which order) when an exception is thrown. In most environment this space overhead shouldn't be a problem (PC, server). But for embedded development it may be a problem. And then disabling exception to save space brings back the issues with error checking (or the lack of it...).
For more details, search for C++ exception implementation and you should find all the info you need. Or look into G++ documentation for example, this topic is covered somewhere.
As for coding standards, I suggest a book by the same author plus the current chair of the standard committee: http://www.amazon.com/Coding-Standards-Rules-Guidelines-Prac.... Another commenter has suggested the Google C++ Coding Standards, but despite their popularity they do not conform very well to "Modern C++" as I understand it.
Many features of C++ are targeted at library authors. Even if a given project won't allow template metaprogramming, it probably uses vector, which certainly does. And for good reason.
In the Java world, a Java EE CRUD application is a LOT different than a Swing application that does the same thing. Likewise, a Python Django application is a completely different beast than a console application.
In C++ you can have such variations, plus all the other paradigms, including:
* C with classes (people programming in this style often still use C strings, do deletes and frees in destructors).
* C++ as the full-blown OOP language, with extensive multiple inheritance hierarchies.
* Nearly functional, STL-driven C++. In this code you see nearly no loops at all, <algorithm> is the control structure.
* Template-driven programming, with policy classes, dozens of specializations, only header files.
Etc. Java does not have the legacy to 'embed' another language. Java does not do multiple inheritance, avoiding heavy-inheritance-based projects, Java does not claim to be a semi-functional language (though Java 8 brings Java closer in that direction), and Java does not provide a turing-complete template language that is a world on its own.
any recommended reading?
As much as I try to find "my" general purpose language of choice, and forr all of my inertia in learning yet another programming language, I believe languages should have narrower scopes. And there should be more languages. Specialized for specific use-cases.
And, as a pythonista, the "you can do/use it in many different ways" just irks me.
This seems to be the curse of any powerful core language (Scala, Haskell, ...) - on the one hand they allow you to make all kinds of useful abstractions that you can't make with e.g. Java. On the other hand, their abstractions are so powerful that they create seemingly different languages.
One could apply the same rule as C++ - stick to a subset of the language/abstractions. However, if you look at e.g. Haskell, a large number of libraries now depend on a library such as lens [1], so often it's not that much of a choice.
Another consistent part of C++ is that it gives you absolute control over memory, both allocation and layout. It's really this control that makes C++ unbeatable in performance. The good VMs can JIT their languages to match CPU performance on small routines, but they can't match C++ when it comes to manipulating big, complicated data structures.
I hate to spoil your worldview, but modern C++ is very alive and well in the scientific computing communities. Disney Animation implemented a new renderer using it, and our next movie is currently being rendered using the new renderer, so I highly doubt it's on its way out in the these areas.
Pharao Inc. built pyramids in ancient Egypt. It cost many lives of slaves but it was cheap them. Nowadays we make big buildings without slaves.
And hey, don't knock the Pharaohs!
First off, it's been known for some time that the Pyramids were built by paid workers:
http://www.boston.com/news/world/middleeast/articles/2010/01...
(Literate too, since they left graffiti)
http://www.bbc.co.uk/history/ancient/egyptians/pyramid_build...
The conditions that migrant workers endure building World Cup facilities in Qatar seem to be worse than those endured by Egyptian construction workers:
http://www.theguardian.com/world/2014/may/14/qatar-admits-de...
That you aren't used to doing greenfield development doesn't mean others are likewise impaired.
I don't know, I've been writing C++ for about a decade and the code I write is "modern" as far as I can tell. I just started a new project. It is C++, it is "modern", and Rust and Go simply aren't options.
Rust is an infant and not yet ready for prime time, and Go simply wouldn't be considered by management. Not because they're ignorant, out of date curmudgeons, but because they want a larger pool of talent to draw upon and a language that is well known, well understood, and has decades of work invested around tooling. I can't say that I blame them.
Why does the "pool of talent" even matters?
There must be something else, like fear of the unknown, risk aversion, "nobody got fired for choosing IBM"…
In the cases the customer is not willing to pay, developers get asked to learn off work hours, if they want to stay on the project.
For ecosystems where there is a "one way to do it", then picking up a random project or library from github and using or changing it is easy, as it is understandable in the same way as my own code; for C++ it is, well, different.
And this is directly caused by the language - the technical details of the language significantly influence the code ecosystem that grows around it. Lisps are another example of this - because it's simple to define commonly used stuff yourself, it results in every project doing the same things differently, adding a serious cost in readability and maintenance for anyone that's not the original author.
For business applications? Sure.
For system programming?
Only if they get an OS vendor godfather that pushes the language into their SDK, like any other systems programming language that got widespread use.
It shows a distinct lack of understanding of why people still use C or C++ to raise languages/environments like Go as viable alternatives.
D is the one true C++ without pretending being a superset of C. Rust is more modern than C++ and better in programming in the large. But D is really for low level programming and a good target for code generation. For me it is a good replacement for C++ and Delphi. It is even a good fit for areas touched by Java and C# like desktop and scientific apps. But it is not there yet because of lack of serious tooling and lack of bytecode but for the second disadvantage you earn performance. Nimrod for example could address this (with D as a code generation target).
Malloc() and free() aren't exactly predictable. If you really want guarantees, you need to write your own custom allocator, and if you don't need those guarantees, garbage collection is probably enough for your purposes.
Basically, if you're using C++ without real manual management, with custom allocators, pools, and all, you probably didn't need C++ in the first place.
This is not to say that the underlying allocator is necessarily deterministic, but you're making a false dilemma here by putting it in opposition to making decisions about custom allocators and pool allocators. You can use RAII with custom allocators. You can use RAII with memory pools.
And that's where C++ really does shine. It's a niche that hasn't even really been attempted much, let alone that it's been surpassed in.
void main() @nogc { /* ... */ } // this program doesn't use the GC
Surely libraries in other languages have the same problem? They don't look anything like each other.
wxWidgets and Qt look nothing like each other but it isn't a problem at all. The signalling mechanism / event handling between the two just hides function pointers, so it isn't a headache. In fact, MFC looks like wxWidgets to me. Not sure what the problem is?
EDIT: Not sure why the downvote(s)? Do people get downvoted here because someone points something out that is true on a subject/language that they like/dislike? Or was it the tone or supposed tone that the person read the comment in? Please let me know!
I like way more of C++11 than I liked of the prior version, but there's just so much that's accumulated over the years. I wonder if breaking backwards compatibility is the key, but then I look at Python 3 and think, well, probably not.
* Don't use var
* Don't use dynamic
or even better,
"You've only got .NET 2/3 installed"
Still no exceptions, though.
The thing is, when you have a single codebase that is maintained by thousands of engineers, you have to make concessions. There is no place for "rockstar programming": everything must be, in a sense, bland, so that it blends seamlessly into the work of thousands of others.
I don't really understand organisations that still use C++ in 2014 but then knock out such fundamental parts of its functionality, but then looking at the design priorities for Go, clearly at least some people at Google have very different preferences to my own, so YMMV etc.
In any case, the decision was made, and we have millions of LOC where every single API is built with the assumption "No exceptions here." In that context, introducing exceptions seems suddenly a lot more trouble than its worth. Well, YMMV, and in any case I'm not a decision maker so what do I know.
* BTW, I think "a single codebase maintained by thousands of engineers" is the single best thing I found in Google, as it opens up infinite possibility of learning new tricks, new APIs, and sometimes new projects. (Of course, everybody complains that every API is implemented at least three times, but imagine how worse it would have been if every project had its own codebase.)
Also no exceptions implies no failing constructors which is plain ugly as a constraint.
In general if you're going to work with other people I believe you need to be a bit flexible on coding with them rather than trying to be hard headed about your own style. It's important that people not be surprised when they work with your code.
I do the same thing. Not because I can't write C++11, but because I still encounter systems with older compilers that I want to run programs on. What, is this surprising?
Let's face reality: it's a little unreasonable to expect every system you work on to have a compiler less than 3 years old.
Especially true on older Linux systems, it's sometimes a massive pain or even pretty much impossible to upgrade the existing compiler in a package-manager-friendly way (try upgrading Ubuntu 12.04's compiler to GCC 4.9, for example), so you'd have to compiler the compiler from scratch. Which is a pretty massive PITA and more or less requires a PhD of its own for GCC (Clang is a little better). And on Windows VC++ isn't always exactly following the correct standard. It's not necessarily outright impossible, but it's pretty impractical.
If you are running Linux, this is one thing that Windows gets right. (Although as you say VC++ has some catching up to do still).
For example I had a building machine running RHEL 5 which was building for both RHEL 5 and RHEL 6 while using gcc 4.8.2 for both (cross compilers).
See also https://en.wikipedia.org/wiki/Cross_compilers#External_links
I've hand-built GCC for half a dozen of different target architectures over the years and it's perhaps one of the most stable pieces of software when it comes to building it. I've only had one build failure over the years and that was unstable from git (even that usually works no problem).
To build GCC, follow the simple steps on the GCC manual. With a modern fast computer, it's all done in an hour or two (of mostly waiting).
If you're dealing with bare metal projects (kernel programming or micro controllers), building binutils and gcc for cross compiling from source is pretty much required. There are scripts that help and some distros have cross compilers in their package managers.
But building GCC is not difficult and it pretty much works first time, every time.
This is your problem.
Build a new compiler using the old compiler and install the entire new toolchain in /opt/my-gcc-4.9-0xfoof . rsync this new compiler to any machine you want. The package managers (people and code) a here for our suffering.
I don't think the idea is to force existing software to be rewritten. It's to provide a clean break so that new software isn't saddled with the baggage of the old. Over time, most of the older software is retired or replaced, and the industry migrates to use the better tools with more and more projects.
This seems a very reasonable strategy, as long as your ABI or equivalent interface specifications can remain compatible for the common subset of functionality, so that programs built using the new language can still use libraries written in the old one. (See also: Every successful general purpose programming language in decades has offered a FFI for C.)
It doesn't work so well if you don't have proper formal standards for your old and new languages. It's also much harder to achieve in practice if your code is effectively running on some sort of virtual machine so you can't have that clean break at the ABI level, which might be one reason why several languages have failed to make a convincing big jump in recent years (Perl 6, Python 3, etc.).
With this argument, every release that adds a new keyword (for example) would have to be given a new name, since it will very likely break some code. Question that remains is how much must the changes be before the thing deserves a new name.
That said it's quite expressive now, you can do a lot with a little code, which is always nice.
Perhaps we should start with dispelling the old notion that one "shouldn't use" the STL.