Hacker News new | ask | show | jobs
by jlarocco 3870 days ago
I wonder how long it'll be before C++ loses its performance advantages. It used to be low level enough that just using it meant you probably got a pretty good performance boost. But if they keep adding features like variants and reflection, and if people actually start using them, it seems like performance will necessarily decline.

Or, if not, other languages will look at C++ to see how they handle these features and keep performance, and improve their compilers.

3 comments

Variants and static compile-time reflection will both be a boon to runtime performance. The former means less heap allocation and better locality and the latter means less work at runtime and better in-memory layout (for example, instead of parsing JSON to a hash map you can copy JSON values directly in to your objects)
If C++ "loses its performance advantages" it will entirely be due to the culture and not the language itself, because you can still do inline assembler in C++. I've long believed that the reason why lower-level languages have performance advantages is because their paucity of "rich" features means their users often find simpler, more efficient ways of solving problems.

I've noticed this even between C++ and C - without classes, inheritance, and so forth, you tend to think a lot more about whether you need something class-like before going ahead and doing it, and many times a simple function is all you need.

Adding new features almost certainly invites plenty of advocates who will opine about how much better they are (which is true in some situations), encourating their use, even if not actually necessary. This is problematic when these features make it easy to generate large amounts of inefficient code.

People often think of C++ as a Object oriented language. That a very old fashioned way at looking at it. Most modern C++ code avoids OOP like the plague. For instance the author of STL (The C++ standard template library) calls OOP, philosophically unsound, a hoax.

http://www.stlport.org/resources/StepanovUSA.html

No need to worry. They only adds zero cost abstractions. As in, no abstractions or features are added that have a runtime performance cost compared to the optimal hand crafted solution. The standards committee is very anal about this. Also the "you dont pay for what you dont use" rule applies. (Exceptions might be an exception)

Compile time has gotten worse though with some new features. Hopefully modules will help cut it back a bit.

I think the term "zero cost abstraction" is a bit misleading. Abstraction means that developers don't have to think about some lower level aspects that they would have given some thought otherwise. That tends to result in inefficiencies.

For instance, C programmers will think a lot more about the size of buffers, how big they need to be, can they be fixed size, can they be reused, etc, because expanding them is often a manual task. In C++ it's so easy to do things like this even though it could be done much more efficiently:

  string parse(const string& data) {
    stringstream result;
    for (char c : data) {
      if (someCondition(c)) {
        result << transform(c);
      }
    }
    return result.str();
  }
I dont think I agree. Abstraction in my view is (mostly) about removing implementation details that dont change from one implementation to another. Its about removing boilerplate until just the fundamental features of the implementations remain. It would be a bad abstraction if details (low level or otherwise) that do change, are removed.

Im not sure I get your example. Are you implying that this C++ code is inefficient because the allocation for result is not done in advance? If you know the size of result in advance, there is no reason to use a stream for result. You can simply use std::string and reserve.

>If you know the size of result in advance, there is no reason to use a stream for result.

Oh yes there is a reason. The reason is that streams are a convenient abstraction because there is very likely an operator<< for whatever transform(c) returns. And why is there an operator<<? Because streams abstract from the type of sink (string, file, network).

You are absolutely right, that this can be implemented a lot more efficiently. That's exactly my point. Abstractions lure us into using inefficient solutions without thinking.

You say "If you know the size of result in advance [...]". Well, exactly. Do you? That's something C programmers think about long and hard but you don't have to think about it if you use streams or even string abstractions naively.

This isn't just a case of "you can write bad code in any language". It's what abstractions do. Allow us to ignore stuff that is unnecessary if the goal is simply to arrive at a correct but less efficient solution.