Edward C++Hands
bartoszmilewski.com
bartoszmilewski.com
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..
My point was that I mistrust all braggart claims about how language/paradigm X will turn water into wine.
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.
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.
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.
I'm not trying to start a flame war or anything, just pointing out that C++ is good at some things you cannot really do with friendlier languages.
1: http://www.reddit.com/r/haskell/comments/1le4y5/the_haxl_pro...
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.
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.
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.
http://www.youtube.com/watch?v=6QrGmA_RR4E
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.
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).
Comparing Python and C is unfair, though. There's a right tool for every job.
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.
"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 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.
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.
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.
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)?
[1] Warning -- anecdotal evidence directly ahead.
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.
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.
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.
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."
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++).
> 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 his opinion.
> and is obviously false
That's your opinion.
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.
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.
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.
"Ease of writing parallel software" was never the question we were arguing.
You wrote this at the top of the sub thread:
> If it was that difficult to implement parallel programming in imperative languages...
Now you want to make it about squandering. You seem more focused on being right than having a discussion.
...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.
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.
Based on which criteria? Citation needed.
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.
Pretty much all languages have handy OS API calls, usually a lot more portable than C/C++ - so that's not a compelling reason.
Yet somehow a lot of new code is still written in C/C++: Redis, Memcached, Nginx, MongoDB, Android, Chrome etc
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.
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!".
[2] https://github.com/charliesome/rustboot
[3] http://thechangelog.com/rust-ko-a-minimal-linux-kernel-modul...
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.
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.
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.
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.
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.
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.
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.
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.
- Bjarne Stroustrup
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.
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."
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.
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?
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.
I'm saying that we could have way fewer bugs and crashes with better languages and tooling.
http://erlang.2086793.n4.nabble.com/infinite-loop-when-beam-...
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."
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
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.
But I don't believe in the one true language.
He said that because his language gets an inordinate amount of complaints.
I actually love how relaxed and non-pointy-headed PHP feels. They seem to have backed off and tried to remake the language as OOP now, which is sad.
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). :)
Can't tell whether joking or serious. I guess my bitter laugh covers both cases.
and other ways being not free is freeing.
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.
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.
Also keeping an eye on Go and D, but not yet committed.
Optimize for effectiveness, not speed.
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).
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.
Ada? I've heard that it is very big on safety, and that it is in the C ballpark efficiency-wise.
I heard good things about many other "nice" languages, just nobody saw them in the wild, actually doing something useful...
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.
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".
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.
Although, it's safe to say if you have 20GB heaps and are doing Gen2s often, then you might wanna investigate another approach ;)
There's a benchmark: http://www.techempower.com/benchmarks/#section=data-r6&hw=wi...
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.
Can you do better?
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]
[0] https://github.com/TechEmpower/FrameworkBenchmarks/tree/mast... [1] https://github.com/TechEmpower/FrameworkBenchmarks/issues/31... [2] https://github.com/TechEmpower/FrameworkBenchmarks/pull/325#...
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?
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?
Can I do what exactly? I'm not your monkey.
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.
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.
"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:
https://www.youtube.com/watch?v=4moyKUHApq4
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.
http://stackoverflow.com/questions/520068/why-is-the-linux-k...
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.
"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.
str[::-1]
While it is in C++: std::reverse(str.begin(), str.end());
And Ruby is even more obvious and consistent: str.reverse()
Most people who rag on C++ have never seriously used it. It's not that bad. Really, it isn't.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
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!)
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.
reverse(begin(str), end(str));The 'corrected C++ version of the code' is actually:
std:vector< int > pod( 10 ); ...
I didn't bother reading any further.
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.
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 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 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.
I'm sorry and deserve to be downvoted.
http://thread.gmane.org/gmane.comp.version-control.git/57643...
My takeaway from experience from all of that is to use C (as Linus argues).
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.
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.
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.
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.
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?
"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.
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?
[Edit] I'm looking for production code, not "in-house" or "internal tools". I did read trough http://www.haskell.org/haskellwiki/Haskell_in_industry
It is used in production by Twitter, Netflix, Foursquare, LinkedIn, Simple, HealthExpense, Klout, 47 Degrees, Box and a long list of other companies [1].
[1] http://www.quora.com/Startups/What-startups-or-tech-companie...
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.
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.]
The sad situation is we have no worthy competitor. Go?
Go is not flexible enough: Required garbage collection, no type-safe generic programming (yet), opinionated concurrency model.
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...
bool CsvParser::OpenCStyle(boost::filesystem::path path)
{
FILE* fh = NULL;
::fopen_s(&fh, path.string().c_str(), "rb");
if (fh == NULL) {
return false;
}
const int BUFSIZE = 1024 * 256;
char buf[BUFSIZE];
m_Records.reserve(m_EstimatedRecordCount);
bool at_end_of_file = false;
std::string carryover_field_data;
std::vector<std::string>* current_line = NULL;
bool at_new_line = true;
const char separator = m_Separator;
while (!feof(fh)) {
size_t size_read = ::fread(buf, sizeof(char), BUFSIZE, fh);
char* start_of_field = buf;
size_t i = 0;
for (i = 0 ; i < BUFSIZE && i < size_read ; i++) {
if (at_new_line) {
m_Records.push_back(std::vector<std::string>());
current_line = &m_Records.back();
at_new_line = false;
}
if (buf[i] == separator || (at_new_line = (buf[i] == '\n'))) {
current_line->push_back(std::string());
if (carryover_field_data.size() != 0) {
std::string field(start_of_field, &buf[i] - start_of_field);
m_Records.back().push_back(carryover_field_data + field);
carryover_field_data = "";
} else {
current_line->back().assign(start_of_field, &buf[i] - start_of_field);
}
start_of_field = &buf[i + 1];
}
}
carryover_field_data = std::string(start_of_field, &buf[i] - start_of_field);
}
fclose(fh);
return true;
}http://stackoverflow.com/questions/9025093/stdcin-really-slo...
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.
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.
There comes a time when no one uses a feature anymore so it might as well be dropped. How many of you still have floppies on your computer?
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.
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.
Would that work?
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).
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.
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).
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.
http://cpprocks.com/c11-compiler-support-shootout-visual-stu...
http://www.reddit.com/r/cpp/comments/1h9uq7/c1114_stl_featur...
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.