First, I must say that I totally agree that Ogre devs should not adopt C++11 right now yet (or at least not the whole standard) for several of the reasons cited before.
The following comments are only because I would like to clarify some arguments that don't always hold to me, even if I agree with most of them.
dark_sylinc wrote:
- The standard library hasn't matured yet
We see arguments in favour of C++11 adoption the usage of std::atomic and std::thread. The problem is, the std lib isn't mature. These libraries have been written in a rush with time constraints and deadlines. And as a result, they favour functionality over run-time performance or compilation speed.
For example, VS 2012's high_resolution_clock isn't high resolution. Not something you would really expect. Some atomic's usage are also several times slower than they should be.
This problem affects all compilers. It would take at least 5 years until the std lib has matured and proven to work as one would expect. Nowadays developers suggest that std::vector<T> should deliver the same performance as a raw pointer. But this wasn't true during the first years. vector<T> used to be a huge bloat. This is normal software development cycle.
While I agree with the arguments, my current estimate is 2 years from now to get C++14 rock solid (note that C++14 is basically C++11 but bugfixed and with a few additional utilities).
The reason is that competition in the c++ implementations made things different from, say, the situation from 10 years ago. Also, this is my intuition from following diverse c++ implementation quality checks with post-C++03.
That's just my estimate, not a disagreement.
- Boost is not a replacement for C++11
We also see as suggestions that when C++11 is not supported, Boost should be used instead (it's far more mature and had been supporting stuff that just recently got into the standard). Here's the shock for you: We're trying to get away from Boost.
In some game companies, you can literally get fired for adding Boost as a dependency to the game engine. It bloats the executable size (and thus runtime performance), increases memory footprint, and greatly increases the compilation time.
While I agree with the general sentiment and practical truth, I believe (from both research and experience) that this is a double generalization, which makes this argument a bit bold and non-credible to me. The first generalization is that all boost is one big block of libraries that all have the same compilation and performance properties, which is just untrue. (see also recent discussions in the Boost mailing list about MS stl implementors commenting that boost get quickly faster implementations than compilers one but compilers implementation get faster after some years. In practice it depends on which library you are talking about, and you might have surprises.
The second generalization is that all game devs don't use Boost, which is plain false. I've seen and used boost even in console games. But of course the choice of libraries to use was very careful, so it's more like a side effect of assuming that all boost libraries have the same defects.
Anyway,...
Boost is useful for simplifying your life in regular programs, but it has no place in low latency, high performance graphics engines.
Which is incorrect as I do have done high performance low latency code with boost. (in commercial projects, games and not games)
The truth is that it depends on other factors specific to the project (technical limitations or knowledge about meta prog most of the time), but I agree that most game companies will generally not use boost (whatever the reason) which is already a good reason for Ogre to not use it either.
Instead we're using our own cross-platform primitives where we can focus on quality and performance while maintaining dependencies and compilation time to a minimum, without the pressure of supporting every use case. Such examples are the classes LightweightMutex, Barrier, ThreadHandle and the functions Threads::CreateThread and Threads::WaitForThreads. A bonus benefit is that debuggers produce a much cleaner call stack when debugging multiple threads. In other words, it's also cleaner.
This is unrelated to using C++11 but:
I partially disagree that it's a good idea or that it helps debugging multiple thread (in my experience) and I do fear that Ogre get in the same issues than with the windowing system being maintained by the team while replacing it by a library focused to do just that (SDL/SFML) makes life simpler. Of course not all features are comparable as some enter the specifics of Ogre but I don't believe that concurrency tools (not use) should be implemented by the Ogre team (but having an interface to abstract them is indeed necessary). I think I already said so before and will shut up on this now.
- Adoption requires modifying coding standards
One of our fears is that contributors will start using auto everywhere. Auto looks awesome to get rid of typing 8 extra letters, but it's very horrible when you have to analyze code written by someone else and you can't quickly see what the variable's type is, or you don't have an IDE to help you.
Auto is useful inside templates, since the variable type may not be known until compilation or specialization, or when the syntax inside the template gets too complex. However using auto outside templates (or everywhere!) is an abuse.
While I understand the cautious stand here, this argument don't match my experience with auto. I tried to abuse it so that I quickly get experience on when not to use it.
Currently I believe that auto should be considered case by case, with or without generic code.
I have tons of example of non-generic code that made auto helpful with code that might change, as long as you keep the semantic clear.
One example:
auto final_orientation = parent.orientation() * relative.orientation();
auto position = final_orientation * original_position;
What is the type of final_orientation? It could be a Quaternion, a matrix or Euler representation, and all would work here. Recently I wrote some code like this and changed several times the type of orientation() return because of some experimentations. The nice thing is that this code compiled without changing, as long as the semantic don't change.
My point is that with experience I realized that "generic code" might not be only template code. So now I consider auto on case by case, easily ditching it as soon as I want a specific type.
Reading the code hardly is impacted as long as you get the semantic easy to understand.
However, I do not believe that explicit float and int manipulation should use auto at all. It's only confusing in this kind of code, you should always make clear what is the type.
So, in most ogre code I suspect that explicit types are indeed better. However that's not true for all the code. Keep in mind the flexibility of not having to change all the user code
when you manipulate a concept instead of a specific type.
In any way, auto in ogre wouldn't impact my code, so I don't object to the decision; just pointing that 3 years of using auto don't lead me to the same conclusions, but with maybe different kind of code.
It can even introduce subtle bugs: e.g.
Code: Select all
auto x = 7.0; //This is a double
auto x = 7.0f; //This is a float
auto x = 7.; //This is a double!!!
auto x = 7; //Is this an int or a uint?
Last line: It's always a int. What made you think it could be uint?
The rule is that it uses the type of the thing on the right, and the type of litterals have been defined even before C++03.
The first one may be intended to be a float, but the 'f' was missing.
The third one may be supposed to be an integer, but the extra '.' made it a double. Easy to miss.
The fourth one is the worst kind. Signed integer overflow is undefined behavior. Unsigned integer overflow is well defined (wraps around). This can have unforeseen consequences:
Code: Select all
auto x = myInteger; //int myInteger = 262144; causes undefined behavior as result should be 68719476736, but doesn't fit in 32-bit
if( x * x < x )
{
//The compiler may optimize this away. Which wouldn't happen if 'x' were unsigned.
}
I believe that calculations with basic types should not use auto anyway, so I get your point and I agree.
However I don't agree when this example is used as a generalization for all kind of code. Of course it's a good argument for graphic code (except the non-mathematical parts).
Most likely we will end up banning the usage of auto keyword outside templates or specific cases. We would have to also analyze what happens with other C++11 additions like lambdas. The point is, we can't just rush and let contributions using C++11 syntax go ahead. We have to sit down and think about it.
I'm guessing that trying to use auto a lot in other projects could help the team get experience for this. Meanwhile I agree that it's certainly the safer way to go for now.
So basically I'm nitpicking (
), but I agree with the global decision.