The H.264 encoder I use is written in a mixture of C and ASM. It is damn fast and maxes out all cores.
I dare you to write a full-featured, functional H.264 encoder in Haskell with equal or superior performance. Once such a thing exist I will start believing the hype.
Until then I reserve the right to consider the current Haskell/FP craze the biggest amount of bullshit since the Java/OOP craze.
Sorry people, I already know that magic language/paradigm which solves all problems of software engineering. Which allows me to write 4 times less code, said code being robust and maintainable practically by default, yet as fast as C/C++ if not faster, all that thanks to this great new model of software engineering! It is the (only) future!
Yes, the Java/OOP/design patterns/UML crowd made exactly the same bullshit claims back then. Nobody talks like that about Java/OOP anymore because the bullshit eventually hit the fan known as reality.
Oh and before Sun's viral marketing campaign there were the Lisp weenies. Again, same bullshit. We already have a "30x less code" language which comes bundled with an insufferable sense of intellectual superiority not backed by practical results.
Oh, and I almost forgot the Python/Ruby "dynamic" and "human" craze. "Programming for human beings" - it's the (only) future!
Back then the snake oil addicts paraded around dynamic typing and code which read like plain English as the salvation of the programmer. Nowadays they claim dynamic typing is the software engineering equivalent of the Holocaust and that good code must look like math!
> Until then I reserve the right to consider the current Haskell/FP craze the biggest amount of bullshit since the Java/OOP craze.
You make it sound as if the consensus following the 'Java/OOP craze' was that the naysayers had it right all along, and we should all go back to C/ASM. Well, it wasn't. Even though it was overhyped, I bet most developers (myself included) would still choose Java over C. Of course this means we would take a performance hit, but for the vast majority of jobs it wouldn't matter one bit.
At the tail end of most of these 'crazes' (Java, Python, Ruby, etc.), once the dust settled we ended up with something that is in many ways far superior to what came before it (certainly when compared with C).
The main micro blogging site I use is a mixture of scala, java, with ruby/iOS for the front end.
I dare you to write a fully featured, async web stack that handles many-core on the scale of hundreds of millions of users in C and ASM within equal or lesser man hours. Once such a thing exists i'll start believing the hype.
BBC did this 15 years ago on tiny computers compared to now. They uploaded static HTML onto Sun boxes and served them.
If you did a submission somewhere, it'd do offline processing and upload new static pages.
Most of this was C and perl.
No Scala, no Java, no Ruby.
iOS does HTML too you know.
I agree with the OP - most of this new technology doesn't really solve any problems. All it does is create an ecosystem you can feel superior being a member of.
Even better, it's a new ecosystem that interviewers will use as a screen to keep out people who don't know the new ecosystem, and so will require people to learn it, and then in 4 years it will be thrown away because no one does that any more. See, they've moved onto the even newer ecosystem.
1) I'm struggling to wrap my head around twitter being cited as an example of software best practices.
2) How many man-hours are we talking about here? How do we get that data?
3) Once such a thing exists i'll start believing the hype.
I think you got that the wrong way around. The "mainstream" programming world has always been imperative (C and C like language). The "hype" is the other way round, Scala/Haskell/Erlang will save us from certain doom etc.
... to be fair, lumping Erlang (millions of production hours in the real world for decades) with Haskell and Scala is a bit silly.
Erlang is battle tested in the field since the late 80's. It just happened that the market (high-reliability, clusterable, multicore systems) came to it so it started to get hype.
I see your point, comparing languages created for robustness and programmer productivity with languages created for raw hardware access and performance doesn't make much of a point.
However, C++ tries to be both, that's what's special about it. It's also arguably the cause of most of its problems and it's complexity, but that is what makes it powerful and useful - for certain applications.
> The main micro blogging site I use is a mixture of scala, java, with ruby/iOS for the front end.
Twitter seems to use Scala for most of their backend (after growing too large for Ruby), but Google and Facebook (arguably operating at larger scale than Twitter) mostly use C++ there AFAIK.
You're probably talking about layers above the web server, but, interestingly, nginx is pure C, async, and scales massively, and it's taking over the web. The creator of nginx is probably a genius, but still...
You gloat, standing atop a hill of technologies, all implemented in C or C. Fundamentally you built your blog in C and C++, you just to do so indirectly, much more slowly by inserting JVMS and other bits in the way.
Can you point out where he claims where any language/paradigm will turn water into wine? It seems to me you are attacking a straw man.
The article claims things like "in C++ the bulk of resource management is memory management" and "In C++ ... there is no guarantee that another thread won’t modify it". These are the evidence he uses to backup his conclusion that C++ is in "direct conflict with the requirements of parallel programming".
So he is talking about more than raw computation speed. He is talking about having greater assurance that certain classes of bug are not present. He is talking about less permissiveness, more restrictions, more checks that the programmer. That hardly sounds like water to wine. More like seat belts and health & safety reviews to prevent accidents with power tools.
What happens when you compile your code into C, like how Vala is done, which now supports Python, Java and I think functional languages like Haskell and Clojure.
What happens when you can compile Python using LLVM for embedded targets like Cortex-M CPUs?
I like C as much as the next guy, but I know how deeply complex, verbose and difficult it can be to program and debug it.
I don't think Python is a craze, I think it's a fundamental philosophy to make a certain subset of computing more approachable and what is wrong with that.
I can do some very simple things in Python and it won't be overwhelming.
Just the building, linking, preprocessor process alone in C is what makes the language almost to difficult to use.
Every time I read a "scathing" attack on C/C++ for being the worst language the author ever heard of, I hear Jack Sparrow's reply in my head "Ahh... but you have heard of me".
Somehow despite the litany of crippling deficiencies, C/C++ have managed to be the foundation of every piece of technology a consumer or a computer professional will ever touch in their daily life. But yeah, other than that, we should all be using.. oh, I don't know, scala or haskell or something like that.
Your point is correct, but it seems like a defensive stance. Rather than debating the technical facets of the article, you fall back on the ubiquity of C++ projects as an overwhelmingly positive aspect. For what it's worth, people say the same thing about PHP; how do you feel about that language?
It's hard reading vitriolic attacks on things you enjoy. There was a talk given by a Rubyist on why he thought Scala sucked, and I found it very irritating (and incorrect). So, that being said, I don't want to dismiss people feeling this way when the subject is broached. It would be nice to find a way to raise these points without ruffling feathers.
...but I think it should still be talked about. Times change, we learn lessons, life moves on. In spite of this, our most-used software is written using a language that is decades old. C+ is not a mathematical theorem...there is no universal truth to it that gives it a timeless quality. It's very common in the medical profession to rapidly change treatment methods - although a majority of the underlying knowledge is static, the actual techniques and tools change as better ones are discovered. In the realm of programming, can't we at least have the discussion?
I'm not advocating totalitarian FP. What I would love is for people to just take some of the biggest lessons learned and apply them. Hell, if I could just get immutability by default (we all know untamed mutability is dangerous), no untyped null (Hoare's billion-dollar mistake), and truly useful first-class functions (with everything that implies), I'd say that's enough to mollify me for the present. Thinking way, way, way forward, I would like to see people really studying and rethinking programming in general. Just because this is how we are doing this now doesn't mean it's the best way. "Normality" is sort of an accident - I'd love to see a more studied approach.
> Rather than debating the technical facets of the article, you fall back on the ubiquity of C++ projects as an overwhelmingly positive aspect. For what it's worth, people say the same thing about PHP; how do you feel about that language?
As Stroustrup fittingly said: "There are only two kinds of languages: the ones people complain about and the ones nobody uses."
How can you know the downsides and warts of something you haven't used in a wide range of applications? Are you honestly saying there won't be any? Granted, an old, proven language will have far more warts than a fresh one that's still idealistic. Fixing old warts introduces new ones etc.
The point I was making (somewhat sarcastically) is that the claims of deficiencies in C/C++ family of languages, such as they are, are way overblown. There are lots of problems with the model of course. The author is not the first person to express his utter dismay at the inelegance and crudeness (as they see it) of this model and won't be the last. They have seen the light. How can the others be so blind etc.
Meanwhile in the real world, every single computing device, billions of them, are working non-stop, days and weeks and months on end, on a foundation of millions and millions of lines of imperative code (mostly a combination of C/C++/java/ObjectiveC ). If this programming model was so horribly broken, so inadequate, so crude, how could mere humans have created such an enormously complex technological edifice on top of such shaky foundations?
> ...how could mere humans have created such an enormously complex technological edifice on top of such shaky foundations?
Mere humans have split the atom, mapped the human genome, walked on the surface of the moon, transplanted organs, achieved flight, cloned a sheep, and invented apple pie. I'd say next to these accomplishments, the act of writing good software using tools that make some aspects of the process difficult is hardly an achievement.
I agree that hysterics claiming we are a hair away from a total imperative meltdown are ridiculous. However, I think that "make some aspects of the process difficult" is a reasonable assessment of imperative, low-level programming. Can you tell me you've never been bitten by an unexpected null? Or, that you've never tired of having to write a class that's essentially a wrapper around a List/Map because the interface is not convenient or fluent?
I'm not suggesting we get a mob together and overthrow the tyrannical imperative government, leaving corpses dangling from the gallows as a warning to the next person who wants to mutate an input parameter. I just want the discussion to move away from "C++ is fine, quit your bitching" - this is totally unproductive.
If medical doctors thought like this, laproscopic surgery would never have been taken seriously since conventional surgery was totally adequate. "I mean, what's the problem? Yeah, being sliced open creates very long recovery times for people and is more likely to lead to infection, but that's just something we have to deal with. An incalculable number of lives have been saved through conventional surgery, so I really don't think we need to consider new methods."
I like your approach. We do need discussions on the pros and cons of languages rather than be so religious or "conservative" about them.
From what i understand, different tools are suited for different tasks. C is even more dangerous that C++ but i am sure everyone admits that it is great for high performance computing. But dangerous as it is, it would slow programmer productivity a HELL LOT if you try to take care of all the possible bugs.
IMO Java and the OOP paradigm is designed for manageability of really large software. it's far easier to group related code together, delegate responsibilities to those classes, and just do inheritance when you need to reuse old code. Not to mention it's designed to let you borrow code from other people and use it with ease. This is very helpful when working in large teams where people can work on separate parts that talk to each other
PS: i apologize for my lack of vision. I have no experience with Ruby, scala or FP languages
"every single computing device, billions of them, are working non-stop, days and weeks and months on end"
working non-stop? No, they don't. Today’s computers are filled with bugs because bad implementations that comes from bad implementation languages and bad tooling.
The reason C++ is used is because backwards compability/legacy/history trumps everything else. Just look at MS Windows for a proof for that. Or x86 CPU architecture.
Those are claims that go against my personal experience (pretty much every device and server system I control has uptime in weeks or months). So unless you can actually show me some hard data to the contrary...
You on the other hand seem to be implying that a different programming model will result in a never crashing system at the scale of the current internet.
Remember Erlang runtime is also written in C ultimately. I would have believed claims about Erlang "never crashes" if I hadn't had to personally debug mysterious hangs in Erlang runtime (running RabbitMQ):
"C/C++ have managed to be the foundation of every piece of technology a consumer or a computer professional will ever touch in their daily life"
That has nothing to do with the technical merits of either language, and everything to do with a small number of early programmers' choice to use those languages -- which left us with a massive legacy codebase and an incentive to keep teaching people those languages. To put it another way, Unix is the reason C is popular and Windows is the reason C++ is popular. People who write software for Unix and Windows have compelling reasons to use C and C++, since every program ultimately needs to interact with the OS once in a while.
Every time someone brings up the crippling technical deficiencies of C and C++, someone responds with a point about C/C++ being popular. All that says is that technical merits are not necessarily a determining factor in language choice.
Well, there is also the difficulty that there has not been, save Ada, a serious and concerted effort to replace C and C++ for so many of the things that they are used for. Except for Ada, no other modern language is suitable for writing things like kernels, drivers, emulators, etc; except for Ada, basically all modern languages are dependent on garbage collection.
So if you want to complain about C, remember that the only serious alternative is and has been Ada, and ask yourself why you're not using Ada, why operating systems and window managers, mupen64plus and Wayland, et cetera don't use Ada, and the truth is: people like C more than Ada.
Ada is the anti-C++. It's the answer to every criticism. It's also basically unheard of outside of situations where people really, really need safety cf. airline industry. In fact most of the people who complain about C++ would never even consider Ada. The author of the article seems to be unaware it even exists, which says a lot.
The takeaway is that safety is overrated, consistency is overrated, reliability is overrated, because if we really cared about these things... we'd use Ada. And we don't, because "Ada is annoying!".
There is another attempt at it. That language has been in development for a few years and is almost ready. Rust combines the best features of C and functional programming and through a very clever pointer system manages to eliminate race conditions, null pointers and dangling pointers at compile time. It has a powerful type system and smart type inference. It's possible to have some memory be garbage collected, but by default it isn't so it can be used for tasks that prohibit garbage collection. The compiler ensures that freed memory will never be accessed. It's built for modern parallel hardware and offers tons of concurrency features, like lightweight tasks, actors, async, etc. Its structs are compatible with C and Rust can integrate seamlessly with C code and librairies. It compiles to native using LLVM. It's backed by a major non-profit, Mozilla. It's a fantastic project and it seems to have all the right cards to be the perfect alternative to C++.
Check it out. My only disappointment (and the reason why I'm not using it seriously at the moment) is that because the language is still in development, it changes extremely fast and 80% of the documentation online is wrong and won't compile. Even the official documentation contains a lot of outdated syntax. Hopefully that will change once the language reaches version 1.0, in the next 3-6 months.
I haven't tried Rust, but what about considering Python for embedded targets?
Is it that the language won't fit, or us embedded people are just too masochistic to find something easier.
You can use something like py2llvm to compile using the same system that Rust uses and get fairly good performance. I am working on this project actually.
Rust[1] is aimed squarely at this use case. The GC and runtime are optional. A toy kernel[2] and Linux kernel module[3] have already been written in it. The language is young and still unstable, but it's being designed by veteran C++ programmers with the goal of using it for a safer, faster, more maintainable successor[4] to the browser engine in Firefox. Worth checking out!
"Except for Ada, no other modern language is suitable for writing things like kernels, drivers"
I think the existence of Lisp machine OSes is a prominent counterexample to this claim. I understand your point, and I would not try using modern Lisp compilers to write an OS, but there is nothing about Lisp that makes it a bad language for low-level code.
> Well, there is also the difficulty that there has not been, save Ada, a serious and concerted effort to replace C and C++ for so many of the things that they are used for.
Except Ada is older than C++, so it cannot be an effort to replace it.
Around the time C was still UNIX only we also had Modula-2.
An advantage C and C++ have over many other languages is that they are part of the standard tooling from OS vendors.
The only way to get people to use other, safer systems languages, is when OS vendors push for them.
For example, Objective-C would be dead if it wasn't the only language to fully explore iOS and Mac OS X capabilities.
Sure you can write bindings in other languages, but Objective-C will remain the language to go to.
The same with any language that would be targeted to replace C or C++. Without OS vendor support, no chance.
> For example, Objective-C would be dead if it wasn't the only language to fully explore iOS and Mac OS X capabilities.
It's a symbiosis. Cocoa would be much worse and harder to program if it wasn't for Objective-C.
Objective-C gives a stable, object-oriented ABI without requiring a VM.
Objective-C runtime is as powerful and dynamic as Python or JavaScript, e.g. you can replace any method of any instance of a class, even ones you haven't defined yourself, and Cocoa uses this for UI bindings.
I haven't said otherwise, just that hadn't Apple not decided to push it, the language would be dead.
This was the reason behind the Cocoa Java support in the early versions, as Apple was not sure if mainstream developers were willing to pick up Objective-C, even with them pushing for it.
It is funny, from what I understand one of the old complaints about Ada was how verbose it was in comparison to C at the time.
Comparing modern Ada to modern C++, C++ has tried its best to equal Ada in verbosity, although C++11 fixed a good deal of C++03's excesses.
From what I can tell, Ada is still missing a good way to do really primitive bit operations in a simple matter. Then again, bit ops destroy Ada's type safety, so I can see why they were made difficult. Still, if one needs to start poking around the individual bits of arbitrary data, C makes that easy-ish. (I mean it could be a lot better, it isn't hard to come up with a better syntax than C's for bit-wise access)
But everything I have read about the latest Ada spec makes it seem like a nice language.
I also believe another problem is that Ada has always been a rather academic language in many ways. Where as for the longest time no one in the C community really talked about pointer aliasing (and I'm guessing if you took a random cross sample of programmers in the late 80s/90s, many of them wouldn't know what the term even meant), Ada requires you know about pointer aliasing just to use pointers at all!
Then there is the fact that the language syntax is defined in BNF, and the main reference pointed to for Ada is the official reference manual. On one hand, hey awesome, the language spec is freely available for all! On the other hand, it is about as readable as any other official spec. The experts who can easily understand the spec end up just pointing to it (after all it is so easy for them to read) and thus simplified explanations don't get created.
> In fact most of the people who complain about C++ would never even consider Ada.
If I had tooling and other people in my group had more familiarity with it, I sure as heck would. Holy crap am I sick and tired of being limited to just straight C and a very tiny subset of C++. And 90% of the new stuff in C++ is not targeted at the embedded market (quite the opposite!) where as Ada has stayed closer to its roots.
It's also difficult to find a compiler, programming tutorials, or a community for. I think there are a LOT of reasons programming languages are chosen by developers and that most of those reasons aren't all that rational or well informed.
Good compiler support, a wealth of documentation, an active community, and a number of well-maintained libraries are all rational and informed reasons to choose a programming language. Network effects matter.
> Unix is the reason C is popular and Windows is the reason C++ is popular.
I never understood why people say C++ is popular because of Windows.
C++ was already popular before Windows mattered.
My first C++ applications were targeted at MS-DOS, back in the days most PC compatibles were still sold with 1 MB of RAM and almost no one has Windows installed.
Before Java was created, many of us were already doing C++ with CORBA in commercial UNIX systems.
Microsoft compilers only mattered to us around the time Windows NT started to enter the enterprise and the 32 bit version of Visual C++ was introduced.
C++ got popular due to its almost 100% C compatibility and as with C, UNIX also contributed to its spread in the enterprise, not Windows.
I am speaking from experience here. The only language I have used where this does not apply is F#, and only if you count .NET support.
I love CL, I never want to go back to C or C++, but the most annoying aspect is the lack of good system call support. Sure SBCL has a posix compatibility layer, but anything beyond basic system calls becomes a drag. In the worst case you wind up having to write a C function to wrap a system call just to expose an easier-to-use interface for the FFI. It is a complete mess, and it becomes a maintenance nightmare.
The author clearly didn't say that C++ was the worst language he's ever heard of. He didn't necessarily even say C++ is a bad language. What I'm reading is more along the lines of "Ok sure, C++ was important at one point in time. But in 2013, we have lots of things to worry about that C++ doesn't help us with that other languages do help us with."
He conclusion is the C++ is obsolete and the power of new hardware capabilities is being squandered because of it. I'd call that 'scathing.' I'll always be fond of C++, but I hope I never have to use it again.
That conclusion on squandering the power of new hardware is being backed by absolutely zero data and is obviously false. Just look around you and note how much software you depend on runs in a parallel fashion on multicore systems (using the SMP model of programming) and is written in imperative languages (mostly C and C++).
The only arguments presented by the author are his own subjective opinions of how bad various features of C++ are. There's merit in many of his arguments but the effect of each problem is exaggerated way beyond it's actual impact. For example, the bold, unhedged claim:
"Two words: data races. Imperative languages offer no protection against data races — maybe with the exception of D."
is a ridiculous claim to make right after his (mostly dismissive) nod to memory model and synchronization primitive introduced in c++11. If it was that difficult to implement parallel programming in imperative languages, we'd have to scrap every OS kernel (which pretty much all scale to large number of cores today) and every hosted language environment (which are all ultimately written in C/C++) and rewrite them in Haskell.
Careful readers (who read the references at the bottom of the article) will note the author clearly has an agenda having to do with more automated resource management in C++. For whatever reasons, it has not found it's way into the standard until now and in his frustration, he's lashing out at not just C++ but basically the entire installed base of computer technology (mostly built on top of imperative, manually memory managed languages like C and C++).
It's worth re-reading the quote again: "Imperative languages offer no protection against data races"
...and this is true. An imperative language (in and of itself) has no protection against data races. That's not to say that imperative languages can't have code without data races. It just means that the language itself offers no protection.
Functional languages (basically only Haskell - I consider Scala an imperative language) have protections due to the Church-Rosser theorem[1], which states that (in essence) pure code can be executed in any order and there won't be any race conditions.
The rub (which is what I think you're getting at) is that it's dubious whether languages like Haskell are practical in a real-life production environment. Imperative languages "get things done", and given judicious use of appropriate libraries may be able to do concurrency just as well if not better than a purely functional language like Haskell.
I don't know any languages that are practical in a real-life production environment. They all kind of suck in their own special ways. What makes you think Haskell's practicality is more dubious than any other?
The author is on this thread, so maybe he'll answer you. Of course you can do these things in C++, but does anyone really want to when there are languages better suited to it?
> That conclusion on squandering the power of new hardware is being backed by absolutely zero data
I believe that the C++ language and its philosophy are in direct conflict with the requirements of parallel programming. This conflict is responsible for the very slow uptake of parallel programming in mainstream software development. The power of multicore processors, vector units, and GPUs is being squandered by the industry because of an obsolete programming paradigm.
It's not an opinion. It's a simple matter of observation. I see software all around me (and I write some of it) written in C/C++/Java and other imperative languages scaling perfectly fine on large scale multicore systems. I use linux, OSX, Android and iOS on a daily basis. Almost all the code running on these boxes is written in imperative languages, much of it written as parallel, shared memory code.
Google (where I used to work, but I don't think I'm revealing any secrets here) runs a gigantic cluster on foundational software almost entirely written in multithreaded C++ with the kernel written in C of course (some of the application level stuff is in other languages, but still a whole lot even at that level is in C++). Almost any large scale, parallel computational systems you could name are written in imperative languages.
To call all of the above "just my opinion" is simply denying reality. There's no further argument to be had unless there's a basic, shared reality ground to stand on.
What you're saying, basically, is that it's not an opinion because you're right. That's...not a very good point.
Pointing out that most parallel systems are written in imperative languages doesn't help. Most systems in general are written in imperative languages, so it's unclear what you're even comparing it to. Imagine standing on a street corner in 19th century England saying, "What do you mean that open sewers aren't as nice as closed ones? Look at all these sewers; they're all open!" Similarly, "but dude, Google!" just isn't responsive to the argument at hand. An easier-to-grapple-with framing might be: if FP languages continue to grow in popularity, will it become much easier to build parallel software?
I don't actually know, and I'm not even claiming you're wrong. And it's a predictive claim, so you could argue the semantics of whether it's an opinion or not. But your argument sucks and your pretense that your view is some sort of law of nature is lame. It's completely reasonable for someone to disagree with you on how good C++ is for parallelism.
The original claim that this subthread is arguing is that the multi-core processes are being "squandered" somehow due to the deficiency of C type imperative languages. I'm pointing out that I see all those multiple cores gainfully and heavily employed using nothing but the imperative languages so primitive, that they are being compared to open sewers of 19th century London at this point :-)
"Ease of writing parallel software" was never the question we were arguing.
The C++ problem with concurrency is not that C++ can't efficiently do concurrency (as you state, it definitely can), but that it can't safely do concurrency, therefore it's a big draw on programmers, debugging and productivity.
Exactly. the reason the parallel computing is being "squandered by the industry" is because it seems to be too hard to do. There is no "ease" of parallel programming and hence no one does it
I was under the impression he was speaking of parallel programming (software algorithms utilizing parallelism,) not sequential code running in parallel.
If you want to get into proper parallel numerical algorithms, most useful programs are C, C++, or Fortran, sometimes with CUDA or OpenCL kernels. I don't think I've seen any large-scale HPC applications in Haskell, as much as like that language.
I'm not trying to be argumentative, I'm just trying to clarify my perspective, which I think the author shares with me and I feel is not being understood. We know what has worked in the past. To me the author is saying functional programming with language features helpful for parallel programming is a better path to take. If I say I believe electric cars are better suited for the future and you say millions of internal combustion cars exist and work just fine, you haven't told me anything I don't already know or addressed features of electric cars that you feel make me wrong. That a large electric car infrastructure doesn't exist yet also doesn't disprove anything. The internal combustion engine is going away and so is C++. That's my opinion.
"I was under the impression he was speaking of parallel programming (software algorithms utilizing parallelism,) not sequential code running in parallel"
The argument was about squandering the powerful multi-core hardware because of deficiencies in imperative languages. No notion of some platonic ideal of a parallel application was raised.
My point is that the "squandering" claim is clearly and obviously false as I argued above.
I agree that the use of the word 'squandering' is provocative and incorrect. reddit points out that he is evangelizing Haskell (FPComplete) and trolling C++ users on Twitter ("I used to be a C++ masochist") He doesn't make his financial bias clear in the article, which would have been helpful for those not familiar with him.
Ouch! Ad personam attacks are a sign of desperation. For the record, I used to work for FPComplete (I architected the School of Haskell) but I quit. It was an interesting experience, having seen a whole complex web site and an online Haskell IDE built in record time by a few Haskell programmers.
Sorry man! If you read the rest of my posts I was agreeing with you. I was just trying to address the reaction chetanahuja had to your article to say I wasn't blinded and had healthy skeptism, but I still agreed whole-heartedly with you. C++ is great for special circumstances but I'd hate to have to go back to it for general coding. Functional programming offers some very intriguing ideas, which I'm only starting to grasp. I don't really mind you being provocative because it provokes and discussion follows.
This quote reminds me of the US Navy saying I used to hear from officers: "A bitching sailor is a happy sailor." Sometimes, but more often sailors have real grievances that higher ups are choosing to ignore. I had a choice to re-enlist in the Navy and later with C++. Didn't happen with either.
Edward Sissorhands is a tragic figure - tragic in the classical sense, the essence of his strength is the source of his weakness. Correct or not as a metaphor for cpp, that, not attack, is the author's theme.
I take the author to be issuing a warning that he wished he did not feel compelled to give, and that warning is that for some programming tasks which are increasingly becoming common the language beloved in his youth is feeling like a Turing tarpit.
Yes, with enough effort the relationship could be maintained, and for many people doing so makes sense for the sake of the kids, but for others like the author, the spark has died and there are younger more attractive "local girls who want to meet."
"You might think of the C subset of C++ as bona fide assembly language which you shouldn’t use it in day-to-day programming, except that it’s right there on the surface. If you reach blindly into your C++ toolbox, you’re likely to come up with naked pointers, for loops, and all this ugly stuff."
It's all rolled into one as far as the author is concerned.
The author definitely does not consider them all rolled into one; the author was a member of the C++ standards committee. That quote is discussing the C-backwards-compatibility baggage of C++ as a design flaw in C++. In the context of C itself, it might not be a design flaw, and the author appears less interested in that question (he's been writing about C++ since the '90s, and doesn't really write about C).
I don't know about you, but I read "which you shouldn’t use it in day-to-day programming" and "all that ugly stuff" to mean a complete and utter dismissal of C as a language even worthy of consideration. Are you somehow getting a message that the author is endorsing going back to the simple days of pure C?
You could believe C is an absolutely fantastic systems-programming language, but believe that in day to day applications programming, it is a poor choice. Actually, I think that belief is fairly common.
I don't think it would be going too far in the direction of looking for a charitable interpretation of the author's statements to consider this possibility.
I think not - C has extremely thin abstractions - it's basically a portable assembler, with all the trade-offs so implied. C++ is a beast of a language that includes everything and the kitchen sink (plus decent backward compatibility with C), and as such is hard to optimize for new contexts (like concurrency), because there are so many interlocking bits that all need to work (ever tried to write code combining templates with class inheritance? It's mind-boggling, and that's likely a simpler example than those the author cites).
Sorry but I have to call bullshit on this.
Even in addition to the passage I quoted which explicitly calls out compatibility with C as the biggest problem with C++, the bulk of the rest of that article is directed towards resource management, starting with dismissing malloc as the worst possible API for memory allocation and going on to bitterly complain about various problems with pointers, global memory, side effects, for loops and any and everything that C++ inherits from C.
The overwhelming thrust of the article is that C++ needs to stop looking like C and has to start looking like Haskell or whatever other functional cool-aid is being drunk these days. If you are interpreting this blog post to be a call to programmers to go back to C, you're not reading the same words that I am.
Call bullshit? Please. Just say you disagree or something. Bullshit implies that I'm intentionally trying to feed you false information. And you've misunderstood. The line of reasoning you quote is about how C++ introduced new and delete to circumvent the follies of malloc and free. But the upshot was that even new and delete had pitfalls that developers fell prey to, so then came tr1's shared_ptr, followed by unique_ptr, which then necessitated, make_shared, etc. Where did I say this is a call to go back to C? Where did you learn how to read?
I think the author is saying that for what C++ is used for, its backwards compatibility with C is an anti-feature, because it's too low-level. That doesn't mean C is a bad language if you want or need that low level of control, just that modern systems programming should be using a higher level of abstraction which can be more efficiently optimized.
90% of people who I come in contact with that claim to know c++: "Hey, I know C++! malloc, strlen, memcpy! Oh and std::cout."
The article sums this up nicely. Pure, idiomatic C++ is beautiful but too many people are stuck using the C constructs when they should be using C++ alternatives.
Yeah, I guess that was ambiguous, wasn't it? C could equally well be the original sin, if one goes by analogy with the whole song. I'm just glad that C isn't C++.
I recently had to maintain C++ code from about 15 years ago. It is nothing like the new C++11. C++11 is a completely different beast, with many enhancements. Looks good - I recommend you read Stroustrup's C++11 book; if you are familiar with C++, the tour of C++ covers most of the new C++11 features.
Have you used it about 20 years ago? I think what we have now is way better than that.
Of course, what was there 20 years ago, language wise, still is there, but IMO that does not make it a legacy language. A language with legacy, yes, but it still is very much alive.
Heard that saying before, but didn't know it was from Stroustrup! That definitely adds to the hilarity.
In that case, let's hope Haskell and Rust move ever more solidly from the second group over to the first :) Always gonna be stuff to complain about. Doesn't excuse C++'s issues.
We know programming is not incremental, often what we did to get 70% of the requirements will be completely useless to achieve the remaining 100%. C++ will take you everywhere, and I find it a solid choice for any project especially because I am often unsure of performance requirements. I can confidently say my C++ code will scale.
So will wire-wrap, but are you going to try wire-wrapping a word processing program? C++ is able to do anything that Lisp, Haskell, or Scala can do, but with at least an order of magnitude more work for any non-trivial project. That order of magnitude can make a difference in getting your project done at all.
"I can confidently say my C++ code will scale."
I can say the same about my Lisp code. In fact, I switched to Lisp to improve scalability over the original C++ codebase, because improving scalability required a higher-level approach. Sure, it could have been done in C++ -- which would have added at least a month of extra work, which I really cannot spare right now.
We all know that the C language is more a low-level system language than it is something else. Especially for this "something else" the use of other languages thrived. C++ since its appearance brought continuously on the table things to cover these higher levels of programming. This is what makes C++ a language that "will take you everywhere". Use newer incremental additions and you will do what Lisp, Haskell or Scala does without that "order of magnitude more work".
"C++ since its appearance brought continuously on the table things to cover these higher levels of programming."
I see two issues with this statement:
1. The attempts to bring high-level constructs to C++ seem to always come up short. Example: it is still not possible to create something as simple as a doubly-linked list using the standard automatic memory management constructs in C++.
2. Low-level issues creep into high-level constructs rapidly and conspicuously. Example: you have an iterator pattern for sequence types, but if you are not careful you can create a dangling pointer (and no exception will be thrown).
This is why I say (and why my experience has been) that C++ adds an order of magnitude of work to any non-trivial project. The high-level features are poorly conceived and muddied by low-level issues.
Assembler will always scale too. The fact that something will always scale does not mean that it really is the proverbial golden hammer. Assuming that you will need scalability for any project regardless of what it entails is premature optimization.
There are also any number of cases where by using C++, you are missing the opportunity to use something more sensible. Some example use cases include data processing using massively distributed Hadoop installations, data analysis using Matlab/Octave or R, scripting using shell, perl, python, or ruby, and web client programming using JavaScript. I can't imagine web client programming counts among your "anywhere", but if you are doing all of these other things and doing them in C++, then I must ask why.
And in my personal experience[1], developer velocity has proven to be much higher in, say, Python than C++, and there are any number of use cases where rapid development is more important than scalability. Do you really find C++ to be the fastest language for a team to develop in (in your experience)?
ASM doesn't scale in structure (impossible to manage) and certainly not in architecture - for example new Intel Haswell's have vectorization opportunities which will cause any code that doesn't use these opcodes to run worse.
Lastly, it is increasingly difficult to beat C/C++ in performance using handmade ASM, especially when comparing tight loop performance in handmade asm and intel icc - although maybe I suck.
Web-client doesn't count in my anywhere because my browser doesn't run a compiled language. That being said backends are often written in C++. A frequently used paradigm is to see some glue language java, python, calling critical C++ routines that are exposed as a library.
Not an easy read for C++ fans like me, especially since it is coming from Bartosz Milewski.
I did try out several other languages and I keep coming back to C++11 for anything that requires scalability and raw performance, like APIs. The same basic server that gets 400 req/sec when implemented in C# ASP.NET achieves 7900 req/sec using C++.
So far I could not find a programming language that does not have similar (or worse) scissors. It's more like "pick your poison" type of choice.
After I learned Scala, my C++ code started to look like functional programming. According to Bartosz that's a good thing, and I did not have to dive into Haskell (yet). :)
With C#, did you try using manual memory management? I wrote a rather high-performance (50K requests/sec, 550K ops/sec) daemon in F#. The big trick was to use my own mem management when it makes sense. I had a ~1GB managed heap, and 12+GB unmanaged.
For instance, you can stack-allocate many objects in C# (strings and arrays, for instance), if you're willing to give up the safety (and if C++ is an option, then you are willing). You can manually heap-alloc managed objects, too, although it gets tricky if they are nested objects. After all, the JIT is just taking pointers to objects and doing stuff with them - it doesn't care where the memory came from (just remember the GC won't scan your manually allocated stuff).
The CLR (unlike the JVM) has native capabilities built right into it. People should take more advantage of such things instead of only trying fully safe C# and then deciding to dump it all for no safety.
To avoid the costs of serialization and deserialization on a per-request basis, I built a little object system that stored all its instance data in a byte array. All internal references were offsets from the start of the array, but what made it fast was that I could read and write in it using raw pointers.
I then recycled the byte arrays to avoid GC pressure, as many were just over the edge of the large object heap, only collectable with gen2 scans.
I had a version working with manually allocated buffers, but it wasn't any faster - GC overhead was only 2% or so.
Go-lang is roughly 10 times faster than ASP.NET (implemented as recommended by Microsoft). Skipping the ORM doubles the speed, but then you lose most of the components, so I'm not sure that's a realistic optimization.
In case anyone is curious what is going on with those ASP.NET TechEmpower benchmarks:
The TechEmpower benchmarks are all about how much overhead you can eliminate. I profiled the CPU-bound ASP.NET TechEmpower benchmarks and most of the time is spent in IIS<->ASP.NET overhead. After I removed IIS and ASP.NET by just using the .NET HttpListener class [0], the result (on my machine) gives Go a run for its money. Hopefully these results will show up in the next Round that TechEmpower runs.
I profiled the .NET TechEmpower tests that access PostgreSQL and MySQL and found that the database drivers had a lot of unnecessary overhead, for example the Oracle .NET MySQL provider does a synchronous ping to the MySQL Server for every connection, even if it's pooled. Plus, it sends an extra 'use database;' command. [1] The PostgreSQL provider also sends extra synchronous commands for every connection. [2]
So C++ is bad because certain functions should be avoided and has no garbage collector. (With C++11 STL normally there's no need for manual memory management or naked pointers.)
C# is good, just you should avoid the garbage collector and 90% of the standard library. Roll your own web server, raw sql commands, have manual memory management, use undocumented calls, emit byte code and there you have: almost 40% of the C++ performance.
I'm the only one who thinks this does not make any sense?
No, I'm not implying any of that. I'm just saying that an important step to getting good performance is profiling to determine the cause of poor performance, then deciding whether it makes sense to try to improve performance in the found areas, then executing your decision.
Imagine the alternative if I didn't profile: I'd just declare that C++/whatever is way faster than ASP.NET, and I'd switch to C++ and open myself to a whole world of debugging memory corruption issues whatnot. Instead, because I profiled, I found the areas that could be improved, I wrote the HttpListener code and I can stay on the .NET platform for all of its other benefits. By following this process I have more options than just "C# blows, I gotta throw it out the window for C++".
In reality, I have probably written more useful, shipped, production C/C++ than C#, so I'm also a C++ advocate, but hey, when it makes sense, and for the right reasons, you know?
I don't understand how you got there from the parent post. The github links look like idiomatic C# to me, aside from avoiding IIS. IIS has nothing to do with C# vs C++ vs anything else.
The application we built did not access the database per request. That was the point of the blob of data that was not serialized and deserialized; it was a disconnected data set.
IIS was used purely as a driver for an IHttpHandler implementation. We didn't use any of ASP.NET apart from implement that interface. We implemented our own AJAX component system before ASP.NET had AJAX controls.
It was fairly quick on 2003 hardware. Further, the blob of data started out with an embedded URL that referenced a private metadata server, with the version of the app included in the URL. The behaviour for the objects in the little heap was driven from code loaded (normally, cached) via that URL. This meant that you could post-mortem a session by loading up the heap almost like you load up a core dump; you could save the heap along with the request if an error occurred, and have everything you needed for a full repro.
The fact that the URL referenced the code for the behaviour also meant we could roll out updates without ever restarting anything, and existing sessions would see the old behaviour until they were finished, but new sessions would roll over immediately to the new code.
For the niche (data entry, specifically for the insurance industry), I have yet to see a better system than the one we built; it was declarative and typed, and if it compiled, you could be pretty sure it worked, and yet had a built-in API for testing. Loading up the aforementioned core dump even had a REPL. Rails is an enormous pile of work and rats nest of polyglot spaghetti by comparison.
To take a specific example, the application code had a definition for the UI for any given page, and knew what controls were on it, and knew their master / detail relationships. The controls had bindings that were evaluated in the context of the object model stored in the little heap, written in a little expression language called Gravity (so called because it sucked in other responsibilities). So when the end-user loaded up a page, the declaration of the UI and its bindings were sufficient to infer what data to send down to the client; and when e.g. a button was clicked, and the model changed, we could calculate minimal updates to send back to the client. Because the framework knew so much about the app declaratively, you had to do very little work to implement things.
Yes, as everyone says: measure measure measure! Sometimes, despite the CLR generating what looked like terrible x64, it went faster than my alternatives. Performance can be counter-intuitive sometimes, esp. in a somewhat complicated environment like the CLR.
Although, it's safe to say if you have 20GB heaps and are doing Gen2s often, then you might wanna investigate another approach ;)
How CLR ninja skills are better than C++ ninja skills? Both might kill average developers.
The named C# implementation came from .NET experts and an army of consultants from Microsoft. The final advice was "yes, C# is easier to develop, but it comes with a price - just pay the price and drop in some additional servers".
The crucial difference is that C# is memory-safe by default, and for most code, this is fine. As another commenter said, manual memory management is available as an escape hatch from the garbage collector if you need it.
To extend the Edward Scissorhands analogy, with C#, you can use scissors when you need them, but with C++, your hands are scissors, so you'd better be careful all the time.
Well first off, if you have something that suits bytes well (for instance, I have compressed indexes that are base128 delta encoded values, so a byte* is good enough for that) - just use the normal malloc routines and call it a day.
For allocating managed objects on unmanaged heaps, you just need to read a bit about CLR internals. The object pointer (so the value of s in "var s = "hello") points to the start of the object data (IIRC). There's a few words in front of that that provide the object type, as well as the sync block (kitchen sync). Arrays have their own little syntax, where they have a type indicator as well as the length.
You can just manually copy those by pinning an arbitrary object and grabbing a few bytes before it. Then you can write those values to arbitrary memory locations, and use that memory address as the value to put back into a managed object reference.
For APIs that need strings, arrays, or other simple heap-allocated objects, but are pure and just return (like, say, String.Split takes an array to hold splitter values), you might get some large wins by stack allocating them.
The parts of my app that were GC managed, the optimization mainly went into reducing the number of objects allocated - at high request rates, even a few measly objects here and there can easily add GC pressure and suck up CPU. (Although, I will say the CLR GC does pretty well with short lived objects.)
You can also use the freedom of memory access to do things like mutate a string, or to change the type of an array (say, from a byte[] to a long[]).
Another common trick is allocating large arrays of structs, then passing ints that "point" to the struct in question. This a: locks the structs in memory and avoids GC if the entire array is over 85K (it goes on the Large Object Heap), and second, you're only passing a single int param, instead of a struct, which can be slow for larger structs.
I went C++ -> Python -> Scala. Still do Python. Don't do C++ anymore for the same exact reasons he mentions. The guy is a C++ hero and to hear him say those things means a lot. I encourage you to keep playing around with Scala. Have fund with the Actor model. Enjoy GC.
It's easier to start from a GC'ed language, and use escape hatches when you need them, then to start without GC and then realize that your program has become a mess because you don't have it.
Many GC'ed languages have such escape hatches. Those that don't, well, don't start writing performance-critical code in them would be my recommendation.
And also, do not miss his point about reference counting just being a form of GC. "Manual memory management" isn't really a thing that exists, there's a whole suite of memory management techniques and alternatives, and it's easy with something like "C++ with ref counting" to actually be experiencing the worst of all worlds (all the work of "manual" memory management with all the disadvantages of GC) if you don't deeply understand what's really going on with your memory.
Funny you mention the "worst of all worlds scenario" because that's exactly what I was thinking about your advice to start with a GC'd language and then escape for performance critical (which usually means huge heaps btw) parts. This plan combines you all the flexibility, predictability and reliable latency of managed VM systems combined with all the safety guarantees of a manual memory managed system.
Read my whole first sentence again. Carefully. I think it does not say what you think it says.
Furthermore, I still don't think you got the point that there is no royal road to perfect memory management. You can't just say the words "manual memory management" and pretend you've solved the problem, or indeed, that you've said anything at all. Many of the same "manual memory management" techniques that you might use are still readily available in "garbage collected" languages. It's not a boolean, it's a rich space. And thus, I stand by my first sentence.
Learning how to manage memory is a tiny fraction of the work involved in writing complex applications, and it's done upfront. Not having to worry about it would only give a proportionally tiny increase in 'enjoyment'.
Indeed, this is exactly the niche that Rust is targeting: C++ performance without C++'s pitfalls. But it'll likely still be quite a while before it's battle-tested enough for everyday use.
7900 req/sec is on my laptop, first try without optimization - and we will need a lot more.
I know Disqus can serve up to 1M/server and they try to patch the Linux kernel to reach 2M. (Not exactly apples to apples since I use SQL transactions, but in the ballpark.)
The .NET never went over 440 request/sec on the server, not even with help from Microsoft. That means either C++ or using 2000 servers instead of the current 400 servers for every major deployment (hospital).
You're seriously serving a billion requests a day? And you're writing new software which is expected to go from zero to a billion requests, full stop? And you're not expecting anything to change between beginning development and production? And, once the software is in production, it's not going to change at all?
I seriously doubt that all of those things are true - in which case you'd probably be better off using a different language. In my experience, it's much, much cheaper to run 2000 servers ($10m capital cost? something like that?) than double the number of software engineers you've got ($Xm a year, continuously?), and doubling the number of software engineers isn't a linear scaling.
It's per deployment 2000 servers with C# or 400 with C++.
And yes, it is currently used by the largest cancer center in USA (MD Anderson), DoD, VA, Kaiser etc to serve MRI, CT, XRay and similar images for diagnostics (PACS).
Furthermore, how optimized was the C#.NET version? C# will even let you drop into C++ if you want..I have a feeling the C# version may not have been tuned effectively.
Yeah I'd guess perhaps it was part of the framework. The CLR's unfortunate use of UCS-2 (2-byte per char) can really hurt in a string processing system. You can easily go from C# to native and back, so who knows. Also, "help from Microsoft" can range widely.
It's still my favorite language. I do respect his thoughts, but when I have systems programming to do, I'll take C++ over anything else any day, warts and all.
We've come pretty far if without blinking it can be said that 8000 API calls per second is fast and you can get there only by using a language like C++, in 2013...
From what I've read it's mostly used in safety-critical applications. The kind where if something is amiss, your plane crashes. It's niche, but it is actually in use. It's not a toy or academic-only programming language, like you seem to be alluding to.
"Ask any C++ guru and they will tell you: avoid mutation, avoid side effects, don’t use loops, avoid class hierarchies and inheritance. But you will need strict discipline and total control over your collaborators to pull that off because C++ is so permissive.
"Haskell is not permissive, it won’t let you — or your coworkers — write unsafe code. Yes, initially you’ll be scratching your head trying to implement something in Haskell that you could hack in C++ in 10 minutes. If you’re lucky, and you work for Sean Parent or other exceptional programmer, he will code review your hacks and show you how not to program in C++."
For those who aren't familiar with Parent, watch this talk:
which introduced me to Stepanov's "Elements of Programming" and the idea that I could be working with better/more reliable/provable abstractions in C++.
That said... after a few weeks of shallowly digesting the material, I started thinking pretty much like Milewski says above: it's great if I can learn to write better C++, but if what I really want is to escape from its specific dangers and general common programming pitfalls, something like Haskell seems like a better bet.
Every time I look to use C++ for something, I come away with the knowledge that I will never know the right way to do it in C++. At least with C I know where I stand.
I think this is why, for instance, the Linux kernel is written in C and not in C++. And this leads to discussions on the Internet which are definitely funny! :D
IME, looking for a "right way" of doing anything requiring some kind of knowledge or technique is a tell-tale sign of inexperience. Pursuing the search, analyzing possibilities, weighing their trade-offs in the light of envisioned use-cases makes you better and more experienced.
Abandoning the search.. well, you'll certainly never get better.
This extends also to things like designing a LAN, database tables and relations, even to martial arts and sports.
Well put. It's like Perl but in self-denial - for each way to do it there's a bunch of people claiming it's the only right way to do it. And it changes every year.
John Carmack wrote a very interesting post about this same topic. http://www.altdevblogaday.com/2012/04/26/functional-programm... To sum it up, he's still writing code in C++, but it has become less and less like C++. His code has become less OOP and more functional.
Big side note, but C++ for me is just... too much. I come to C++ from Python, and they are just so far from each other it hurts. One of the fundamental things about Python that I loved was:
"There should be one-- and preferably only one --obvious way to do it."
Meanwhile, the sage wisdom I heard learning C++ is:
"C++ is wonderful because there are so many ways to do anything."
These two methods of thought fly right in the face of each other, and it's very hard to reconcile. With Python, I felt like I truly was learning a language, a language of action where doing any one thing was consistently defined. With C++ I feel like I'm in an ocean of choice and ambiguity, having to carry around this huge load of tribal knowledge to get anything done.
Not saying it's a bad language, just sharing my feelings on it.
That's one point against python, and half a point for C++ [1]. By my accounting that leaves the score still hugely in python's favor when it comes to obviousness and consistency.
Python vs Ruby is another subject entirely. Largely I feel like it's mostly a narcissism of small differences situation, and have only been doing more Python than Ruby lately because more people around me are Pythonistas than Rubyists at the moment.
1] ideally you wouldn't have to tell the reverse function the starting and ending points for the string unless you only wanted the reverse of a substring
begin() and end() return iterators. Python has iterators too, so this concept shouldn't be alien to Python programmers. reverse() is a generic algorithm that operates on any pair of bidirectional iterators.
Actually, in C++, you ideally wouldn't reverse the string at all... you'd just call str.rbegin() and str.rend() to grab the reverse iterators, and pass them straight to your next algorithm.
The two approaches are just as consistent as one another, Python just uses a terser syntax (which, in my opinion, isn't as obvious).
In C++14, if all things go according to plan with Concepts Lite, you'll be able to write a short 3-5 line, reusable, version of reverse() that takes your string (or container) as one argument, deduces at compile time, during overload resolution, that begin() and end() return bidirectional iterators, and then does the right thing. Failing that, C++14 may introduce Ranges. So C++ is only getting terser.
It would have been nice to have some sort of simple range syntax added to C or C++ long ago. In the true spirit of C, don't even make it safe, just make it bloody well work.
FirstArray[0..3] = SecondArray[4..7];
case 2..10:
for(int i : 0..ArrayLength)
for(int i : ArrayLength..0)
(hah that'd prove horrible if ArrayLength ended up being a negative number, obviously some proper syntax would need to be determined :) )
I am always annoyed that such simple things are ignored in the language. Sure they don't enable any "cool new abilities", but they make using the language a lot more friendly (especially in comparison to having a ton of case fall through statements!)
Well, there's always reversed(str) for Python (I realise this returns a reversed object and not a string object, which is something I dislike immensely).
I've always looked at [::-1] as being a bit of a hack, even though we use it all the time for both strings and lists.
You're right, C++ is like a huge load of tribal knowledge. It's not like a monolithic language, it is like a group of languages tied together, a swiss army knife if you will. Try take them gradually, in the order of their historical development: C with its preprocessor, then C++ classes with all their stuff, then generic programming (templates), and finally - in-depth stl. You may be told that it's best to start with stl because it was developed for (among other things) the beginners to avoid shooting themselves in the foot, but I find it to be just a coverage for higher-level programming (used best when you already know its under-the-hood low-level stuff).
> C++ “solved” the problem of redundant casting and error-
> prone size calculations by replacing malloc and free with
> new and delete. The corrected C++ version of the code
> above would be:
>
> struct Pod {
> int count;
> int * counters;
> };
>
> int n = 10;
> Pod * pod = new Pod;
> pod->count = n;
> pod->counters = new int [n];
> ...
> delete [] pod->counters;
> delete pod;
The 'corrected C++ version of the code' is actually:
Regarding his assertion about reference counting: Apple's implementation of ARC for Objective-C doesn't handle cycles (it requires the engineer to reason about weak and strong references in order to prevent memory leaks), but it is certainly a "serious" implementation. The fact that it doesn't have facilities for detecting and releasing cyclic references makes it definitely not the "other side" of the GC coin.
That being said, ARC-style reference counting is more limited in terms of what developers can do with their code, and it may not be a general enough solution for a language like C++ (which strives to be all things to all people). Weak pointers in Objective-C also require runtime support, which could probably not be appropriate for high-performance applications in many cases.
> The power of multicore processors, vector units, and GPUs is being squandered by the industry because of an obsolete programming paradigm.
It’s worth addressing these in turn. In reverse order:
I dispute that the C paradigm squanders GPUs. OpenCL and CUDA are the two most prominent languages written with GPUs in mind, and both have a lot more in common with C than with Haskell. In particular they eschew functional mainstays like recursion, linked lists, and garbage collection. So for GPUs, it seems like the ideal paradigm is closer to C than Haskell.
For vector units, there’s some recent excitement about auto-vectorization in Haskell. But I’m skeptical about the potential of auto-vectorization in general, since it only seems to apply to simple loops, and can’t take advantage of all instructions. Most effectively vectorized code uses either compiler intrinsics or outright assembly, and I don’t see that changing any time soon (I’d love to be proven wrong on this though).
Lastly, multicore processors. C++11 more or less standardized the creaky POSIX threading model, with some additions like thread locals - hardly state of the art. I wonder if the author is familiar with other approaches, like libdispatch, which provide a much improved model.
One last observation. Parallelism is not a goal! Improved performance is the goal, and parallelism is one mechanism to improved performance. If your Haskell program runs at half the speed of a C++ program, but scales to twice as many cores so as to make the overall time equal, that’s not a wash: it’s a significant win for C++, which did the same thing with half the resources (think battery drain, heat, other processes, etc.) Horse in front of cart.
>I dispute that the C paradigm squanders GPUs. OpenCL and CUDA are the two most prominent languages written with GPUs in mind, and both have a lot more in common with C than with Haskell. In particular they eschew functional mainstays like recursion, linked lists, and garbage collection. So for GPUs, it seems like the ideal paradigm is closer to C than Haskell.
I think the more obvious explanation is that it's much easier to write a compiler for C than for Haskell. Thus the first tooling available for any new system is almost always C. It doesn't mean C's the best tool.
>For vector units, there’s some recent excitement about auto-vectorization in Haskell. But I’m skeptical about the potential of auto-vectorization in general, since it only seems to apply to simple loops, and can’t take advantage of all instructions. Most effectively vectorized code uses either compiler intrinsics or outright assembly, and I don’t see that changing any time soon (I’d love to be proven wrong on this though).
We'll have to wait and see on this.
>Lastly, multicore processors. C++11 more or less standardized the creaky POSIX threading model, with some additions like thread locals - hardly state of the art. I wonder if the author is familiar with other approaches, like libdispatch, which provide a much improved model.
My experience is that alternative approaches to something as fundamental as parallelism never take off, because they can't gather an ecosystem around them (I'm looking in particular at the chaos of approaches available in perl and especially python). I think a modern language needs to have a single, obvious, preferred way of achieving parallelism/concurrency that libraries can build on top of (and that's why javascript has been so successful - while it's a terrible language in many ways, there is one and only one way you handle parallel-type problems, and it's (slightly) better than the standard way in other languages)
I did work for Corensic, which was bought by F5. It was a company that made a very ingenious data race detector. I learned a lot about data races and how they prevent companies from adopting concurrent programming.
I also used to work for a Haskell company, FP Complete, but I quit, so I'm no longer representing them. I learned a lot about building actual applications using Haskell at FP Complete.
Do you think anything in that link is relevant to this article or did you just want to get in on the C++ bashing and had nothing to contribute of your own?
I think its relevant, honestly. C++ is a pile of hacks, layer upon layer, that only a small highly talented set of programmers can manage to master and the rest shoot themselves in the foot with. Linus says that in his own way, but that's the truth of the situation: C++ is a mess.
My takeaway from experience from all of that is to use C (as Linus argues).
> Yes, initially you’ll be scratching your head trying to implement something in Haskell that you could hack in C++ in 10 minutes. If you’re lucky, and you work for Sean Parent or other exceptional programmer, he will code review your hacks and show you how not to program in C++.
Don't underestimate "instant gratification" even when it comes to programming languages. Yes you might code yourself into a mess further down the line, but most of us are in the business of shipping software not worrying about its correctness.
I'd argue that Haskell (which is what I use professionally, can't speak for Scala) lets you write your less well designed code for shipping, and then refactor it later into something clean. There's a very low cost to changing code, so you worry less about getting it right the first time.
But in some cases like mine you have legacy code. You still have to ship new features and bug fixes. If I get to green field something really new, then Haskell or Scala might be on the table but currently they are not options. Not even embedding them.
Haskell is creating a new value for every parameter / function return value; That means that even for trivial tasks it is churning over non trivial amounts of RAM; the footprint of a Haskell program is therefore rather large; I guess that makes it rather impractical for real systems.
But of course, this one is an interesting observation:
"If nature were as serious about backward compatibility as C++ is, humans would still have tails, gills, flippers, antennae, and external skeletons on top of internal ones — they all made sense at some point in the evolution."
I guess C++ is like Perl: for many things there is more than one way to do a thing; Don't like exceptions? Disable during compilation and code as in C with error codes; That's what makes the whole thing malleable; the right kind of flexibility is a winning feature.
"It’s a common but false belief that reference counting (using shared pointers in particular) is better than garbage collection. There is actual research showing that the two approaches are just two sides of the same coin."
Yeah. But RC is at least deterministic and controllable side. Also, RC is just one of options of C++, while you can implement GC yourself in C++ without any overhead unlike any memory management method on GC.
Without compiler support for precise stack maps and barriers (and I don't know if it's actually possible to implement them, given how malleable pointers are in C++) the best you can do is conservative stop-the-world GC. That sacrifices a lot of performance over the incremental or concurrent GC algorithms you see in runtimes like the HotSpot JVM.
This jumped out at me too. I don’t think this point was carefully considered.
For example, the Linux kernel uses reference counting - see https://www.kernel.org/doc/Documentation/kref.txt . Does anyone doubt that this mechanism is better than attempting to garbage collect the kernel?
RC is much more deterministic than GC. Garbage collectors commonly defer object deallocation until some threshold is reached, and then do it all at once. This means that two iterations of the same loop, that do the exact same thing, may take dramatically different amounts of time.
Reference counting is more stable and predictable, because the deallocation behavior depends only on the object graph in question, and not on some global state.
His entire rant about resource management is misplaced. It's not that new/delete/pointers are "bad" or retained only for backwards compatibility, they are primitives from which other abstractions are built. I don't think its too much to ask professionals understand simple concepts such as RAII, which renders his entire example trivial.
This is the first thing that he says during his keynote:
"So, in the next couple of days you're going to hear a lot about the latest and greatest in C++, You're going to hear a lot about advanced techniques and new features. And I decided that in the keynote I couldn't go too much into that, so I'm going to do the opposite. I'm going to try and focus on what is the essence of C++. What is it that has been constant over the decades and what it is that that keeps C++ alive and kicking."
It was clearly framed as a history lesson about C++'s strengths, so I think it is a bit disingenuous to claim he was teaching resource management to a crowd of advanced C++ programmers.
Bartosz, Haskell was created 23 years ago, before Java.
What is the reason it did not catch on yet? Will that change?
I'm not aware of any even mildly successful system that uses pure functional languages.
Most of the implementations I know about is either C/C++/ObjC or JVM. Some Python (Youtube, Dropbox), one .NET (StackOverflow) and pretty much that's it.
What do I miss?
It is used in production by Twitter, Netflix, Foursquare, LinkedIn, Simple, HealthExpense, Klout, 47 Degrees, Box and a long list of other companies [1].
When Herb wrote his free lunch article, I was still a strong C++ believer and I thought C++ could solve the multicore problem. I considered Haskell a toy language. Then I saw how quickly Haskell moved into the multicore arena with STM, Repa, Accelerate, and how C++ kept stumbling in the dark. After the C++11 fiasco I realized that C++ was a blind alley. Multicore revolution did to C++ what the Chicxulub asteroid did to dinosaurs.
You should use standard algorithms whenever possible. Sean Parent talked about it at Going Native. He was able to transform a horrible set of for loops he found in Google's code into a few lines of modern C++ using standard algorithms. But he _is_ Sean Parent!
I love hearing this from OOP insiders. Virtual functions are particularly awful to track down, and are probably worse than GOTO ever was. At least GOTOs only went to one place.
> But you will need strict discipline and total control over your collaborators to pull that off because C++ is so permissive.
Except it's not. The key is proper encapsulation into classes and generous use of private instance variables.
The real problem is social: people want to get something done quickly, so instead of talking to the original author[1], they put a new method in the class (or declare a friend) and happily continue hacking, without thinking of far-reaching consequences of whether unrestricted (that's what public is) use of the newly introduced method violates class invariants in some way.
[1] I'm aware that the original author might not be there anymore. Which makes a good case for documenting design and intent of the code. A QA matter.
How does Haskell solve the social problem (directly hacking something into a module you don't own or fully understand)?
> What you don’t realize is that it will take you 10 years, if you’re lucky, to discover the “right way” of programming in C++
IMO, only novices and beginners look for "THE right way".
Advanced people realize that the "right" way depends on the broad context and look for (the) best compromise solution among a spectrum of solutions.
I believe this holds for other computing-related things (designing a LAN, database tables, etc.), as well as real life (sports, martial arts, even everyday things like sitting and walking as any person who has had a lower back problem will tell you).
The problem is again social: novices and beginners who refuse to "grow up" and who know just enough to be dangerous: they can produce working but messy code, and refuse to learn other ways of doing the same thing in an appropriate context. (E.g. when to use while vs for, or why copy-pasting large chunks of code between different functions is generally "bad".)
Somehow I'm not convinced that Haskell is the magic bullet which solves the underlying social/human issues.
> Haskell is not permissive, it won’t let you — or your coworkers — write unsafe code.
He never defines what "unsafe" is. Mutation is not unsafe per se.
> Don’t be fooled: accessing atomic variables is expensive.
I've seen recent slides where the measured cost of an uncontended locked cmpxchg on Haswell was ~20 cycles vs ~5 cycles unlocked. This is NOT expensive, unless unnecessarily you replace all memory accesses with their atomic equivalents.
> Most importantly though, threads are not a good abstraction for parallel programming
No, but they are an essential building block.
> Haskell is way ahead of the curve with respect to parallelism
First, a computation can be abstraceted into a data dependency graph.
Now, the reason that most of today's applications don't benefit a lot from the vast number of processors available is not that the underlying programming is somehow unsuited for parallelism.
It is because that there IS NO parallelism available in these applications: data dependency graph is mostly serial, and if parallelism is available, it is on such a small scale that superscalar CPUs already make use of the large part of it.
Also, with overly fine-grained parallelism you WILL end up in a situation where the overhead of atomic operations becomes non-negligible, even if it is only ~20 cycles.
I believe that if people more often thought about their designs in message-passing terms, the dependency graph would also emerge, and they would see that there often is very little parallelism to extract through explicit parallelization. (Note that writing to a shared variable is just an extremely simple and efficient method of sending a message).
This was also remarked on by Knuth: During the past 50 years, I’ve written well over a thousand programs, many of which have substantial size. I can’t think of even five of those programs that would have been enhanced noticeably by parallelism or multithreading. [http://www.informit.com/articles/article.aspx?p=1193856]
So, IMO, easier coding for shared-memory parallelism is one of the worst reasons to switch programming languages.
That's why I personally prefer Erlang-style concurrency (actors). Communication patterns and parallelism granularity is explicit, and communication cannot be decoupled from synchronization. [With shared variables, these two are decoupled.]
I'd consider myself a 'C++ programmer' - I've used it for years, it works very well for me for what I do with it, etc. However, what I find most frustrating is that nothing is intuitive. And there is always a reason for why it is like that, I know. My favorite example is the erase/remove idiom.
Anyway, here is a question about C++. Last week I tried to implement a parser for a subset of CSV - one-byte-per-character, fields separated by comma, no quoting, fixed line ending. The only requirement was speed. So I started with a simple C++-style implementation, read one line at a time with std::getline, split with boost tokenizer, copy into vector of vector of string. But it was too slow, so I reimplemented it C-style - boom, first try, 30 times faster. Through some micro-optimisations I got it 30% faster still - copying less, adding some const left and right, caching a pointer. So if anyone is so inclined, how would I make the following more C++-ish and still get the same speed? Using fopen and raw char* to iterate over the memory buffer are what I'd consider the non-C++ aspects of it, but feel free to point out other idiom violations...
I think your 'or' might be misleading, with the (a) incidental and (b) required. I deal with a number of smart C (and even C++) programmers who view it as assembly with macros. But I've yet to meet any assembly programmers who view C as just a more succinct way to write assembly. Maybe it can be phrased as "Anyone who conflates C and assembly has probably never compared the output of their compiler with the code they think they wrote".
If he replaced "int * _counters;" with "vector<int> _counters;" he would have lost nothing and gained a lot of control. As for the pointer to the Snd object itself, in many cases it is sufficient to create object, not pointer, and pass the reference of the object, then in case of exception memory is always freed no matter how many ints he has push_back'ed and where the exception occurred. And if he really needs to have pointer, then he should create that pointer not in naked function that could return at any time, but make it a member of a class and delete the pointer in destructor. Then make that class as object, which will always execute its destructor, therefore always freeing the memory.
The problem is not that C++ is hard, it's that Haskell doesn't solve the same kind of problems.
We would all love programming to be easier, for the compiler or interpreter to just know what we really meant, rather than what we actually typed, but sometimes the tools are sharp, are a bit more manual, exactly because they offer more control.
The constant sell of Haskell or Go as the panacea for all programming problems is like someone else telling us all to adopt socks made of rubber - a few make like that, may even blog and evangelise about it, but the rest of us find it uncomfortable and annoying.
You would, but the person shaking Edward's hand would not.
To stretch the analogy, scissors are dangerous, but they're also very useful.
I prefer a language that lets me put away the scissors when I don't need them, so I don't cut someone's hand off. For example, Python with C bindings. The problem with C++, IMO, is that it doesn't let you put the scissors away.
Yeah, amongst all the "MS has lost its way" chatter recently, I don't think anybody noted how it's treating C++ devs. Annual full releases of VS? Really?
I think the "use D or Go or rust" or "there is no alternatives" debate has run its course until people actually do big projects in rust.
I do feel sorry (to the extent you can feel sorry for somebody who probably makes $150k+) for the guy in reddit who's started to talk about features he desperately wants in the C++17 spec.
The fact is that there's a very huge amount of legacy code which provides irreplaceable functionality. What would you do if you had a complex data crunching library in C to be integrated into your program?
Rewriting stuff from scratch is sometimes good, but usually you prefer to have some well-tested routines, and be sure they will not fuck up.
Edit: you may also argue that projects like LLVM make it possible to compile stuff in IR, and still keep the old code... but there may be situations in which choosing a different compiler is not an option.
Both CLang and GCC have "C++11 compatibility" switch, so it's a matter of a compiler parameter if they accept or not the new standard.
I would introduce a "backward compatibility" switch that has to be turned ON per source file to accept old constructs. All the new code from now own would be nice and shiny. There's an (easy) way to still keep around old code.
Only if you like writing all your libraries yourself.
To answer a little less flippantly, you'd need to add some sort of "unsafe" construct to the language, because most of the nice, high level abstractions have nasty low-level stuff buried in them, and because of the way C++ templates are compiled, that's all code that will be included in any program you write. In short, all "new" code is built on top of an awful lot of "old" code, and if you were going to make a huge breaking change like this, you may as well write a new language and libraries ground up (like Go or Rust).
Furthermore, even if you restrict yourself to the new stuff, C++ is not memory-safe. C++ would need some sort of Rust/Cyclone-like lifetime/region semantics to become safe.
Scala has the same debate - there are a couple constructs only library writers use (normally).
So they compile the library with "enable all". Everybody else gets a warning and they refactor the code or turn on the switch to allow.
The difference is that you can separately compile your Scala libraries from the code that calls them - if you do that in C++, you give up templates. All those #includes at the top of your C++ code are basically just dumping code into your source files, and if you're using templated code, it macro-expands with parts you're putting in from your own code. There are some separately compiled C++ libraries, but most of the standard library and Boost code you use is recompiled every time you compile your program. You could probably define a new pragma that would tell the compiler that all the code from a given file, class, or function is unsafe, but it would take source-level modifications to every library you use to properly implement the flag you suggest.
And my point was that, due to the way C++ is designed (specifically, not having a proper module system and having this massively powerful macro-replacement templating engine), there is no way for the compiler to distinguish between "legacy" code and "new" code.
Consider the following case study: you have a library including a template class that uses raw pointers as an iterator type. You accidentally write `iter + 9` instead of `*iter + 9` when you've included it (this will likely compile, though there should be a warning). Now, even assuming there's some language extension added to mark that library as "legacy" (maybe #include-legacy <mylibrary>), can you tell me whether the "new" code you just wrote using raw pointers counts as "legacy" or not?
I think this is basically Bartosz' point as well - that C++'s legacy design features are too baked in to make positive changes easily, or even tractably (even small changes like your --no-legacy compiler flag).
Yes, there's a way. Precompiled headers already do a pretty powerful analysis.
Thinking a bit more I realized I just reinvented the wheel: this is how Microsoft phased out the sprintf, strcpy and so on.
So you can choose between 3 compiles modes: --new-cpp --advanced-library and --allow-legacy
You can turn it on with pragma before including an .h file and turn it off after, if you have to.
By default "--new-cpp" is on, throws error on naked pointers, new, delete, pointer arithmetic and so on. Basically C++ would become a safe language, almost like a CLR-type managed code. It could even have a "const by default" variable declaration, like Scala.
The "--advanced-library" would allow a lot more (e.g. manual memory management), and "--allow-legacy" would be for full backward compatibility.
Does it worth it? I think it does: currently with meta programming, lambdas, named(!) closures, deterministic constructors etc. C++11 is one of the best programming languages for anybody who cares about performance.
I dare you to write a full-featured, functional H.264 encoder in Haskell with equal or superior performance. Once such a thing exist I will start believing the hype.
Until then I reserve the right to consider the current Haskell/FP craze the biggest amount of bullshit since the Java/OOP craze.
Sorry people, I already know that magic language/paradigm which solves all problems of software engineering. Which allows me to write 4 times less code, said code being robust and maintainable practically by default, yet as fast as C/C++ if not faster, all that thanks to this great new model of software engineering! It is the (only) future!
Yes, the Java/OOP/design patterns/UML crowd made exactly the same bullshit claims back then. Nobody talks like that about Java/OOP anymore because the bullshit eventually hit the fan known as reality.
Oh and before Sun's viral marketing campaign there were the Lisp weenies. Again, same bullshit. We already have a "30x less code" language which comes bundled with an insufferable sense of intellectual superiority not backed by practical results.
Oh, and I almost forgot the Python/Ruby "dynamic" and "human" craze. "Programming for human beings" - it's the (only) future! Back then the snake oil addicts paraded around dynamic typing and code which read like plain English as the salvation of the programmer. Nowadays they claim dynamic typing is the software engineering equivalent of the Holocaust and that good code must look like math!
I am so tired of it..