C++11 FQA anyone?
yosefk.com
yosefk.com
You'd expect `==` to work in PHP because it compares value. With a char* reference the syntax and everything around it indicates that you're working with well... pointers (and you shouldn't be having char pointers for strings anyway). Don't even mention PHP references etc.
C++ still has a lot of going for it - no one thinks it's terribly great and awesome - but the reason people ridicule PHP and admire C++ is that it solves a much bigger problem.
- In PHP you don't have resource management, the process kind of just dies and resources get deallocated. In C++ that's not acceptable for perfomance. - In PHP you have memory safety - oh wait you really don't, if you do silly things like use raw references you can still get screwed.. experienced C++ programmers don't fall to that pit either. - In PHP you don't have to explicitly deal with memory which is again because you're solving a much easier problem. When your whole world is an immutable page request response cycle life is rainbows and sunshine.
Comparing languages is always ridiculous and populistic but that comparison was just bonkers. Not that C++ doesn't have quirks - it sure does, but comparing it to PHP is just silly.
(Not saying anything about PHP being a bad or good language here, just that the comparison is ridiculous)
We have long running PHP processes for months at a time (hey, code reuse) and they do not suffer memory leaks. Works great actually!
However, for desktop applications and short-lived processes, freeing app-level resources is pointless and only bad for performance. Why bother running through a destructor chain when you can keep your external data clean and just kill -9 the process? This is how iOS makes you work anyway.
The Gold linker (written in C++) doesn't ( http://www.airs.com/blog/archives/362 ): "[I]n the gold linker I often deliberately omitted destructors, because many of the data structures live for the life the program; in such a case, destructors serve only to slow down program exit."
However, there are some things that you really want to know happened when the process exits for any reason. If possible, you'd probably like your files closed in a way that allows them to be re-opened. That's easy to do with destructors. Destructors: they were always for more than just memory management.
That doesn't help with data corruption coming from the environment. The power going off on your machine, your external drive, a crash in your process or an external signal all won't give you time to exit.
There are libraries worth relying on for this, like SQLite. It's not in C++.
Anyhow, as you implicitly acknowledge, destructors help with orderly shutdown, even if the shutdown is caused by an error condition. I prefer them to try...finally that other languages rely on. I can live with C#'s IDisposable, but I personally have a better chance of getting my destructors right than implementing IDisposable correctly (remember, in a garbage collected language, you don't have a defined order that things will be destroyed in).
But, on the completely different topic of how to do disaster recovery when both your program and the host operating system are shut down in a non-orderly manner: I personally am not aware of any language features in any language that make that easier. However, I know it can be done in C++ (stasis ( http://stasis.io/ ), SQL Server, MySQL/MariaDB, Firebird ( http://firebirdsql.org/ ) and SciDB ( http://www.scidb.org/ ) are all implemented in C++, although they aren't all necessarily object oriented C++).
Yes, they do. Empirically.
But yes, it does look like he's gone very far out of his way to try to find things to complain about.
I have observed someone do this: _myarr[5]={0}; – they had in the
.h file the definition int _myarr[5] and they remembered that this
thing could be initialized with {0} in other contexts. What they
did wouldn't compile in C++98; in C++11 it promptly assigned the
int 0 to the non-existent 5th element of _myarr, and the usual
hilarity ensued. Imagine how PHP would be ridiculed for this kind
of little behavior – and PHP at least would never overwrite an
unrelated variable with garbage. Imagine how with C++, the poor
programmer will be ridiculed instead.
Let me repeat that one more time, the poor programmer will be ridiculed instead.
From your response, (and you shouldn't be having char pointers for strings anyway)
[...]
experienced C++ programmers don't fall to that pit either
This is what the article is about, about what you are doing again. C++
is weird, it has a bunch of unusual behaviours, and when pointed,
people who fall into those traps are the ones ridiculed, instead of
the language.I don't know if C++ could have been made less weird with the constraints that it had, as others have pointed out in this thread (C compatibility with no overhead). Perhaps it couldn't be. But this article is unhappy with the attitude of defending C++'s weirdness and then blaming the programmers for falling victims to this weirdness.
So, yes, comparing char*s is very different than calling strcmp; and if you want to use "==" to compare strings (so you don't have to remember to call strcmp), then use std::string.
This isn't to say C++ is the best it could be. There are plenty of outright mistakes. But on the whole, C++ is weird and complicated because it had to be, at least to a much greater degree than PHP.
It's the exact opposite. Close-to-the-metal, the syntax is actually very friendly - you've got values, and you can bash them in like a half-dozen ways. C is incredibly simple (I suppose their pointer syntax is a little janky, but one can always express it "one level at a time" via typedefs).
The really complicated parts come from making high-level operations seem "easy". There is no close-to-the-metal notion of char* vs a string, or a lvalue vs an rvalue, let alone template metaprogramming.
"Hello, World!"
…is a null terminated array of chars. When literal strings are not, in fact, strings, this is a problem with the language. It's confusing, you see? Underlying semantics nonwithstanding, how on Earth the followig works: (std::string)"foo" == "foo"
and the following may not?! "foo" == "foo"
These are not basic concepts. These are trivia. I know there are reasons for these confusing rules, but they're still confusing. You should not mock the programmer for forgetting them now and then.Just like you wouldn't see Python code relying on mutable default values or JavaScript value relying on `with` semantics or Java code relying on `URL` comparison through DNS very often - you shouldn't find code that relies on `"foo" == "foo"`.
I'm sorry if my comments are harsh but I really do believe C++'s issues are mostly cultural.
Of course you should never rely on `"foo" == "foo"` and other such things. Still, one would expect literal strings in the language to be of the preferred string type. C++ is the only language I know of that breaks this expectation. It does not follow the principle of least astonishment. That, is not a cultural issue.
That said, I'm willing to accept that C++ do have cultural issues. Could you tell me what they are?
I think it's only fair seeing as this article accuses Bjarne of "evilly shrewd" moves, maliciously crippling Cs development, and "knocking C it in to a coma". So watch it for Bjarnes perspective from his own mouth. You may as well see get a biased view from both sides.
One thing I don't particularly agree with is that some of his examples of C++ code use features that will not be made available for years, likely around or after 2017 when C++17 should be standardized. This is assuming compilers implement the standard quickly, which is worse on some platforms than others (cough Visual Studio cough). What I'm specifically talking about is any example that mentions concepts, but at least he is clear that concepts are only currently available in a branch of GCC.
[0] http://features.slashdot.org/story/14/08/20/011231/interview...
The syntax for concepts seems pretty well set now, and Alex Stepanov (author of the STL, and worked with Bjarne on the new concept model), in his Amazon A9 lectures (available on YouTube) recommends you simply #define concept names to "typename" so they at least exist in your code as documentation.
The most important thing however is really to get people writing their generic code with a concious awareness of what their type requirements actually are, and then to document and specify them correctly, just like you'd rightly expect a function written in C99 to specify clearly what the pre and post conditions are... something the compiler can't help you with even today.
If your compiler isn't tracking the standard well, don't use it. The truth is that C++14 is just got ratified now and already open source compilers have implemented most of its capabilities. Concepts are a bigger kettle of fish, but compiler makers have also had much more time to work on them, so I wouldn't assume we have the huge lag problems we used to have with standards adoption.
I understand people going back to pure C, but man, as screwed up as C++ is it's hard to give up things like vectors and strings and namespaces.
Everything else has a memory model that doesn't quite work, and look, I like GC as much as anyone but sometimes you need a language where you can turn it off when you need to guarantee there isn't going to be intermittent GC pauses.
Rust especially.
In contrast, the design of C++ was constrained by the goals of
- Compatibility with C (and later previous C++ standards)
- Zero overhead / you do not pay for what you do not use
- No GC
Those constrains are responsible for most of its ugliness, not poor design.
It's impossible to have a heap allocator without overhead. How much overhead you have depends on the design constraints and the trade offs. Particularly if you are dealing with more sophisticated constraints like memory fragmentation and other issues, a GC might actually be an easier and lower overhead way of solving the problem.
More importantly, you missed the most important aspect of the second point: "you do not pay _for what you do not use_". You and copx would be surprised to know that pretty much since the standard committee started working on it, garbage collection has been something on the table for C++, but they've never been able to get a proposal that everyone was happy with.
I also think that the "No GC" category is perhaps not the right name. What C++ was really about was making UDT's first class types and therefore supporting value semantics. A side effect of that is that GC isn't nearly the priority it might otherwise be.
GC can be much faster than malloc() when allocating objects, depending on the GC scheme used and the heap profile, allocation savings may outweigh the cost of collection.
So "No GC" is a completely separate point.
In contrast, there are many languages that can do the job of PHP.
To be sure, there are languages that aim to challenge C++ on its home turf, but it will take a lot of time and a lot of work before you will see a relational database written in Rust (or insert your favorite C++-killer here).
EDIT: spelling and grammar
Linux says otherwise.
There are other reasons that C doesn't scale well to large software systems. For example, C's relatively limited compile-time error checking, which leads to using conventions (especially naming conventions) to enforce good practices where tools and good typing would do the job better.
But GC, VM, OS - all those TLAs can and should be written in kosher C.
The actual origin of the saying is quite different:
But this is really a side issue to my original point: C++ and PHP are categorically different since there aren't strong alternatives to C++ for many types of problems. Though it is possible that other languages are eating at the edges of what C++ is good at.
The success of C++ provides a wealth of evidence that C isn't really up to the task -- everyone seems to hate it for its complexity, but very few people are writing web browsers in C89 these days.
2. Blaming C does not explain C++'s undecidable grammar, the zillion ABI incompatibilities introduced on top of C, lack of an alternative for #include coupled with features like inlining and templates making it a disaster that it never quite was in C, or many other of C++'s faults. How is PHP's grammar a worse design than C++'s? I really want to know. I think PHP's is better.
3. Source compatibility with C does nothing for the user (who could have lived with ABI compatibility just fine) and everything for Stroustrup (who managed to make his language that much more popular by an Embrace, Extend and Exterminate approach).
4. Design goals inevitably resulting in a bad language are bad design goals. If I said that I designed an electric car that electrocutes you but that's because it's compatible with an electric chair for which there's a lot of existing demand, would you then publicly defend me?
5. PHP is a child of Perl which is a child of shell, awk, sed and C. A lot of heritage there to blame as well. So?
6. PHP doesn't byte one's behind nearly as badly as C++ and that's why the double standard exists; because only a fraction of the people who try manage to ever get anything done in C++ and a large subset of these people feel entitled to be treated as an "elite". PHP programmers cannot afford to delude themselves thusly because everyone can be productive in PHP... A funny outcome, I find, given that it "should" have actually led to PHP being praised.
I also believe the grammar could have been made much better while maintaining C compatibility. The language design seems more like throwing stuff at the wall and rolling with whatever kind of sticks, than fully exploring the problem space. See the export keyword: implemented once, and then removed as worthless, not even bothering with the step of deprecation, at the recommendation of said implementation.
Of course it does. If it's poor design, one just don't use the language at all. If it's constraints, any language that solves the same kinds of problems will be just as bad, and - life just sucks - one must stop complaining.
For greenfield development, sure. Many and maybe most of us don't work in that space.
Of course it does. I'm a "user" of C++ and all three of those constraints are very very important to me. There's pretty much no other language (in common use with lots of vendor support etc.) with the power of C++ that follows the same constraints. The constraints are the very reason that C++ is still so popular despite all the complexity (and seemingly an extremely hostile group of critics trying to warn everybody against using it.)
2. PHP was never designed to even support objects in the first place. The API is super inconsistent in terms of parameter ordering and naming. Contrast that with the vast majority of the STL. Sources for the zillion ABI incompatibilities comment?
3. How about, oh, IDK, OpenGL being a C interface. Lua? The Linux kernel? X11? Driver interfaces in general?
4. The big presupposition here is that it's a bad language. Honestly, I'd like to see you design a language that does what C++ allows you to do much better.
5. C was arguably way better put together than Perl was. Perl is an abomination to be honest.
6. What are the use cases of C++ compared to PHP? C++ is used to do things like author renderers, or physics engines, or mathematical simulations. Trust me when I say that attempting to accomplish any of those to the same volume with the same hardware on PHP is madness.
3. OpenGL, Lua FFI, Linux… have nothing to do with source compatibility with C. And everything to do with ABI compatibility. C-with-classes was a preprocessor that generated C code remember? That pretty much guaranteed ABI compatibility, since it was then compiled by the same C compiler.
But what did it matter if the pre-processor where also capable of parsing plain C? It doesn't! We have a C compiler, why not just use that? If stroustrup wanted to, he could have replaced the braces and semicolons by mandatory indentation, Python style, and lose zero backward compatibility in the process. Or at least, no compatibility that actually matters.
Source compatibility was a useless constraint that lead to a painful language. From the user's point of view, the difference between a useless constraint and a bad design choice is nil.
Now I will concede one advantage of source compatibility: learning curve in the extremely short term. If you don't even have a few hours to learn a different syntax, it makes sense. But if your intend to use a language for more than 2 weeks, it's silly to suffer any long term cost just because you don't want to pay that learning cost up front.
Seriously, stop listening to your guts and look at the facts.
As for gcc setting up some kind of example for upgrading to C++… C and C++ are low-level systems languages. They are not suitable for static compilers. While I understand bootstrap as a validation technique, it is not worth the hassle of suffering such a mismatch between the language and the problem domain.
Static compilers should be written in an ML dialect, or Haskell, or maybe Lisp. C and C++ have no business here. And if you really want the bootstrap thing, then you should also implement a DSL that compiles to C or C++, and use that to make your compiler.
As for ML and company being a better choice than C++ for writing a compiler... There may well be convincing arguments for this position, and if I asked you, no doubt you'd give me some. But I'll ask something else instead. Most compilers I heard of are written in C or C++. Name me a compiler written in ML/Haskell/Lisp. There's just one rule: no bootstrapping. Meaning that if you show me a compiler for ML written in Haskell, that's fine, but a Lisp compiler written in Lisp is not.
Two reasons: first, change what sucks (like the useless clutter with braces and semicolons, or the switches that fall through by default). Second, add more features on top of what we have.
As much as I hate C++, we do live in a C dominated world, and C is… limited. The lack of a usable generics system is crippling. C++'s destructors really help with semi-automatic clean up. And it would be good to have a module system, and maybe built-in support for algebraic data types. (I must not overdo it: if I end up turning C into ML, I should use ML. Or Rust.)
> if I asked you, no doubt you'd give me some.
I'll give you one: Algebraic data types, which are virtually unmatched at representing abstract syntax trees, and basically any intermediate representation a compiler can come up with. Other arguments here: http://flint.cs.yale.edu/cs421/case-for-ml.html
> There's just one rule: no bootstrapping.
Of the top of my head, I don't recall any compiler that doesn't bootstrap. In any case, I fully expect that most compilers are indeed written in C and C++, not in ML or Haskell: C and C++ are that popular.
I also happen to think our industry as a whole is mostly nuts, retarded, and short-sighted.
This is not a feature for a programmer to use to make their work easier, rather this is a hook to infect the code, spread the disease and live where other nicer things wither.
C++ is like mold. Yes it is ugly, and you don't want it, precisely because this is the most efficient life form compatible with your stale food, whether you want it or not.
Mold is the most popular pet people have, because it is so hard to avoid. Lice (PHP) were too, but today it was mostly eradicad thanks to better hygiene.
Why does any mention of C++ bring out these silly metaphors that contribute nothing to the conversation?
It makes it possible to use C definitions directly and inline with no conversion overhead or indirection. When your work is writing fast code, the ability to leverage existing fast code damned well is a feature.
>C++ is like mold >you don't want it, precisely because this is the most efficient life form compatible with your stale food
You don't want mold because it causes respiratory and neurological problems. C++ does not cause respiratory or neurological problems, unless you count the insanity it inherited from C like, "A character is the same thing as a byte," "A pointer is the same thing as an array" (which isn't even actually true within the language, unless you count parameter declarations), and my personal favourite, "The mathematical value of false, the cardinality of the empty set, and the identity of nothing are all the same thing. After all, they have the same representation!"
That is achieved with ABI compatibility. You don't need source compatibility however. At worst, you'd have to re-write the prototype of the C function in your own syntax-incompatible language.
Think of it as a zero-overhead FFI.
>ABI compatibility
In other words, conversion overhead and indirection, respectively. There is no substitute for having an inline definition available at the point of use.
Well if you're worried about writing overhead, there are many FFIs out there that parse the header you want so you don't have to repeat anything.
But if you believe for a nanosecond that we need source-level compatibility to get the benefits of inlining… Just remember how C++ first worked: as a pre-processor, that generated C code! So it's all C underneath, and GCC and LLVM and MSVC and ICC can all do their crazy optizations accros the whole project, should you need that.
And in any case, C++ is no longer source-compatible with C. And it no longer work as a pre-processor either. Yet I doubt it has the disadvantage you talk about. C++ has many faults, but overhead with the C FFI is not one of them. Which means we have an existence proof for the assersion that source-level compatibility is. not. needed.
You do. Yes, there's LTO, but to do it effectively relies on storing source code or information derived from it in the intermediate object files. Without the source, the best you can do is try to inline what is hopefully a reasonably well-behaved hunk of object code without any of the high-level information associated with it that the compiler threw away when it emitted it.
>C++ has many faults, but overhead with the C FFI is not one of them [...]
I'm not sure exactly what you mean, but if you're talking about the runtime overhead of calling an extern C function, then that is very much a fault. Inlining can make all the difference in the world with respect to performance in an inner loop, the classic example being qsort and std::sort, and to take advantage of that, source-level compatibility is needed.
Now, if you said that source-level compatibility were better achieved using a fully-fledged FFI than by stuffing all but the worst (well, some of the worst) of C into your language, I would whole-heartedly agree with you. If C++ had done the former, it would be a much cleaner, much less popular language, and instead of using a warty language with templates, useful user-defined datatypes, and function overloading, we'd all be using a warty language without templates, useful user-defined datatypes, or function overloading. Hell, many of us still do anyway.
Is there a list somewhere that describes what the "bad parts" (in the Crockford sense) of C++ are? Bad practices, bad feature interplay, etc.
I've been thinking of writing a little C++ transpiled language of a limited feature set to make prototyping certain things easy. It would try to follow the accepted best practice conventions. I imagine it to be Coffeescript-like, with no separate header files, support abbreviated syntax, syntax for managed pointers, etc. It would probably follow a rudimentary linking scheme.
It might be opinionated in ways that turn some people off: const vars and args by default, virtual methods by default, auto virtual dtors, and probably other "sensible" (in average usages) default patterns.
Finally, I would want to generate simple intuitive interfaces that are linkable to existing C++ headers.
Anyways, this would just be a side project for fun. I don't do C++ professionally. Just for robotics and lasers and hobby stuff. Any information on best practices and bad C++ usages would be awesome to have if I undertake this.
The good bits everyone agrees on are parts like <algorithm>, and oh man, I have a hard time imagining how you'd make that easy to follow.
Your comment kind of makes me question my understanding of the different subsets issue... Would you mind elaborating? I could really stand to understand this better. If you can't expand on it, thanks for giving me something to look into. :)
* Inheritance-heavy subsets, which avoid templates in favor of dynamic dispatching.
* Template-heavy subsets, which avoid dynamic dispatching in favor of templates.
* Subsets avoiding exceptions.
* Subsets avoiding RTTI (dynamic_cast and friends).
* Subsets avoiding pointers (including smart pointers).
* Subsets avoiding the use of container libraries.
* Subsets avoiding the use of <string>.
* Subsets avoiding the use of <iostream>.
You can search for large projects' style guides. For example, Clang uses C++11 features BUT they avoid RTTI and exceptions, which is a relatively common choice.
The one thing which stops me from writing more c++ is all the setup you have to do to actually get an executable. In python I can just create a file, import some stuff and run it. In C++ I have to deal with makefiles, vs projects, paths and all that crap. Just give me a C++ where I can write "import boost.xyz" and the compiler figures out what that means.
It compiles to C though, not C++.
It has a bit more of a Pascal flavour to it, but it is the nicest implementation of a compiles-to-C languages I've seen.
[1]: http://yosefk.com/c++fqa/changelog.html
Perhaps Stroustrup is referring to the JVM and CLR, respectively?
That said, if you know what you're doing it's a great platform.
I love the language and use it alot... but sadly, in many ways, this FQA is just too true.
> <PROGRAMMING_LANGUAGE> is not without it's shortcomings and hidden pitfalls. After all, there is a reason that any style guide for <PROGRAMMING_LANGUAGE> will include a large list of features that should not be used.
This holds true of pretty much any language. Take a look at Google's extensive style guide library [1]; they all contain language features that should be avoided for any language. It all just reflects the iterative nature of programming language design.
There is almost nothing in there that sounds like a landmine. Rather, some general guidance about "don't use global variables," "x may not be thread safe," and "don't write overly complex lambdas."
My favorite "gotcha" in Python is using e.g. a list as a default argument. That's in the guide, and it sucks, but Python has surprisingly few such problems for newcomers.
Really I think one of the best things to be pointed out about C++11 is that YosefK's response is... a little disappointing. Sure, he makes some good points (I liked the "array[5]={0};" mistake), but really this isn't nearly as strong an indictment as the original was. Frankly modern C++ is a huge step forward (though obviously traps remain), and this is as good evidence as we'll see.
The expert part is required just to cope. The good taste part comes from the requirement that other people must comprehend your code. i.e. it needs to be simple, pithy and correct. Some languages make it more obvious how to reach this goal than others, while in C++ I see this being mostly the result of trial and error. You require taste, restraint and experience not to implement your production solution in some unmaintaineable template-class-Gang-of-four mishmash "just because you can" and because "it's the C++ way".
The main problem with all this, IMHO, is C++'s continuing popularity. There are some problem contraints where it still is the best tool for the job but those contraints should be well understood and realized when selecting it as the implementation language.
> C++ works great for millions of programmers who get it
I feel this is a huge productivity loss for the industry as a whole. C++ creates a huge bureaucratic burden on the developers where they must spend their efforts to trivial minutiae and not in value adding work. C++11 improves on this considerably, though. I do not presume to impose some other language on those developers - rather my point is that the issues the FAQ author raises are real and that since lots of people are using the language the severity of these issues is multiplied by the number of people using it.
Note: I'm a developer who mostly writes C++ in an industrial context :).