Moving to C++11


#1

Inspired by https://github.com/urho3d/Urho3D/pull/1818
Are there any plans to migrate to C++11 and break old compilers support?

Urho doesn’t seem to be rapidly developed right now. It may make sense to publish some stable C++98 version and then go to C++11.


Urho3D 1.7 release pending work
#2

Apart from JSandusky’s upcoming PRs, it’s true there’s not a lot going on, so yes it sounds like a good idea to push a stable version out in near future.

After that it’s fine by me to break old compiler support, at least I test old VS versions very rarely by now.


#3

Then I want to raise another question.

C++ has nasty trend to bring style ambigity in new standards. I think that codestyle guidlines have to be updated and most of new C++11 features shan’t be used in Urho core code.

For example, there are some ambigity in the following cases:

  • Variable declaration: explicit-type vs auto
  • Type declaration: typedef vs using
  • Variable initialization: A a = 10 vs A a(10) vs A a{10}
  • Member initialization: : a_(10) vs a_ = 10 vs a_{10}

I suggest to avoid in Urho core things like auto, inplace member initialization, curly braces initialization. All typedefs are probably may be converted to using since it is not hard ‘regexpable’ change. Also, nullptr IMO shall be used instead of pure 0. Some overrides are also useful.

I suggest it not because I hate C++11, but because I thing that style consistency of Urho costs more than minor benefit from syntax sugar like auto.


#4

I like initialisation members in class

class A
{
    int b_ = DEFAULT_VALUE;
}

This allows not forget initialisation for members (such errors have repeatedly been)


#5

auto can be used in iterators i think


#6

I like inplace member init too! However, Urho shall IMO use either such notation everywhere or nowhere. So another option is to rewrite class declarations step by step into new style.

auto can be used in iterators i think

Such exceptions will also lead to inconsistent codestyle.


#7

First of all I disagree with the “all or nothing” approach because it usually means not doing anything because it will take huge effort and in the meanwhile you just pile up more legacy code, which makes it a huger effort which means it becomes less likelier, which means more legacy code, recursively, which converges to the “nothing” part of the “all or nothing”.

I’m in favor of writing new code in the most optimal way, and going back to refactor old code when revisiting it or when there’s nothing better to do.

regarding new C++11 features you mentioned, they aren’t a style choice.

auto

  • removes the need to maintain and refactor code when changing types
  • eliminates the possibility of implicit conversion bugs
  • less writing. Container iterators are a good example
  • more readable. Container iterators are a good example
  • easy to use. No need to look up what type is being returned and such

I only know 2 cases when you shouldn’t use auto - if you write something like an number type (f.e. auto = 0), in which case the intention behind the value itself is ambiguous (0/0.f/0.0? char/short/int/long?).
Second case is expression templates, in which they return some abstract reference instead of evaluating the expression.

Alias declarations (using)
Personally I prefer their syntax because it’s similar to variable assignment.
Alias declaration is compatible with templates, so AFAIK it’s always better than using typedef so there’s no reason to use typedef anymore.
http://stackoverflow.com/questions/10747810/what-is-the-difference-between-typedef-and-using-in-c11

List initialization
This one is nuanced, and shouldn’t be used everywhere possible.
http://stackoverflow.com/questions/18222926/why-is-list-initialization-using-curly-braces-better-than-the-alternatives

They’re usually preferable because they provide better type safety & correctness.
On the other hand you can write a constructor that takes an initializer_list and that means calling class{x,y,z} may not be the same as class(x,y,z)

Other features that can be useful constexpr, lambdas, unique_ptr, ranged for loops, Expression SFINAE…

BTW, we could use Clang Tidy to automatically refactor things to C++11.
Perhaps it can be used with CI too (?)


#8

When auto are everywhere it is very difficult to know what type of returns some functions. Currently I open any file on github and know it without looking function definition


#9

In Visual Studio you just have to hover over a variable/function too see a tooltip with the type.
I assume this is a basic IDE feature.


#10

Even when I am writing my project in Visual Studio I am using Alt+F7 in Total Commander for search in engine sources and F3 for looking, so no any tooltip xD


#11

I mean that there shall be somebody who has enough passion to refactor old codebase step by step to new style. E.g. I prefer inplace initialization and I am ready to periodically migrate old stuff.

auto

Absence of auto was the best thing in Urho codestyle. Yes, I dislike auto.

removes the need to maintain and refactor code when changing types
eliminates the possibility of implicit conversion bugs

I have never faced such bugs, so I think they are quite rare. However, I can also imagine bugs that are caused by implicit changing of type of auto variable. So it eliminates one kind of bugs and introduce another.

String A::foo(); // -> const char* foo()
...
auto a = foo();
if (a == "1") { ... }

less writing. Container iterators are a good example

Of course, impossible to argue. I use auto when WIP or for some simple local projects.

more readable. Container iterators are a good example- easy to use.

No, no, no, NO. auto is more readable for some complex temporary types and it completely ruins readability in most other cases. It literally brings strong-typed language into don’t-give-a-fuck-about-type script language like python.

  • It’s harder to explore code via file manager
  • It’s harder to code via browser
  • It’s harder to review diff in classical merge tools
  • It’s harder to review diff in browser
  • It’s harder to visually check dependencies of some piece of code
  • It’s harder to determine type usage among codebase
  • Search became useless

Programmer saves a minute by writing auto. Readers waste an hour/day/??? by reading this mess.
So… Almost-Never-Auto is my choise.
Almost-Always-Auto guys say that reader don’t need to know about the type.
I say that if writer is writing code for people, he has no right to decide whether the reader needs type or not.
Almost-Always-Auto guys say that variable name is enough.
I say that type name is a ‘part’ of variable name and dropping of type is almost like dropping the name.

The worst thing is that experienced developeds have an immunity to such auto disadvantages because they are familiar with codebase and they really don’t need explicit type. Problems started to appear as time passes, old developers forget codebase and new developers come.

In such big project as Urho, usage of auto IMO shall be strictly limited. Otherwise, its currently perfect readability will be partially destroyed.

This one is nuanced, and shouldn’t be used everywhere possible.

It is just almost unneeded. So I see no reason to bring inconsistency to codebase.

Huh, I finihed.


#12

I encountered bugs that auto would avoid, implicit conversions.
Your auto “bug” example is wrong, it just shows you don’t understand what auto is. if you don’t want to use the type foo returns you shouldn’t use auto.

auto doesn’t disable strong typing, I’m not sure if you know what that means.
It isn’t dynamic typing, you can’t change the type of a variable defined with auto, and it’s statically checked.

all auto does it tell the compiler “this variable is of the same type that is being assigned to it”. If that’s your intent, auto is the correct way to write your code.

Did you use auto? I never encountered any of the “harder” problems you describe.
I suspect the reason is because they’re problems caused by not using auto in the first place, like changing the return value of a function and now you have to use search to replaces all the types of the variables that use it.

Herb Sutter had a talk in CppCon 2014 - “Back to the Basics! Essentials of Modern C++ Style”, at ~28:20 he talks about auto:

Show me a better way to initialize a vector with the following values than this:

std::vector<int> v{5, 10, 3, 9, -3, 2500};

#13

He can say any thing, but if I had to guess the type or move mouse to read the tooltip, it does not simplify my life :slight_smile: it just slows down the perception of the code


#14

I open random files:

    XMLElement rootElem = file->GetRoot();
    XMLElement paramElem = rootElem.GetChild();
    UI* ui = GetSubsystem<UI>();
    UIElement* uiRoot = ui->GetRoot();

Imagine this code with auto.


#15

std::vector<int> v = {5, 10, 3, 9, -3, 2500};
is good enough

auto doesn’t disable strong typing, I’m not sure if you know what that means.

I didn’t say ‘disable’. I meant that strong-typed language with auto loses its readability advantages and became scripty.

Did you use auto?

Yes.
I always use auto in small projects that I am not going to maintain. It’s okay.
I also use auto at work because it is our style. I put up with it.

I never encountered any of the “harder” problems you describe.

I did.
Have you ever tried to explore big infamiliar codebase written in AAA?

Look at @1vanK example and imange that you know nothing about types XMLElement, UI and UIElement.
How do you recognize this piece of code then?

auto rootElem = file->GetRoot();
auto paramElem = rootElem.GetChild();
//< These guys might be similar, yep?
//< Nodes of some hierarchy, probably. What hierarchy?
//< Values or pointers? Must be values because I see dot.
//< What about const?

auto ui = GetSubsystem<UI>();
//< Ok, here I can guess the type. It is some singleton.
//< So it's non-unique pointer
//< Is it shared or raw? What about const?
//< Probably it is just UI*, because it is a singleton.
//< Or maybe weak ptr, who knows?

auto uiRoot = ui->GetRoot();
//< No ideas WTF is it
//< Root element of some hierarchy.
//< Is the same type as rootElem from first part of code??

#16

I had to make this:

:^)


#17

I hope you understand that IDE tooltops is not a solution for explained problem.
Code shall be readable enough for reviewing via notepad/browser/difftool/etc.
Code is all that we always have. IDE is optional.

So, briefly, my thoughts and proposal:

  • auto saves time when writitng code
    • It is the main advantage of auto and the main reason for programmers to use it
      • Other advantages are less important and affect some rare corner cases
  • You can comfortable work with auto variable if one of the following conditions is true:
    • If you ask IDE for tooltips (i.e. use mouse when reading code)
    • If you explore variable context (i.e. spend time on checking related functions and objects)
    • If you are familiar enough with codebase/architecture to guess the type by name and context
  • Explicit variable decalration is easy to read and understand without any conditions or extra effort.
    • So explicit type is objectively more readable than auto
    • Exception: ugly big types
      • Probably such types need or already have an alias
        • If they don’t, auto is a perfect solution!
  • Programmers always say that good readablility is more important than quick writing
    • Why auto shall be an exception?
  • It’s not so hard to replace dozen of autos in your commit when you finish your work
    • Especially with these nice tooltips
      • Why not to make life easier for others?

#18

Consider the following piece of code:

int x = f();

Can you know the return type of f() from reading it?

The answer is no.

auto isn’t about quick writing.
If that’s your understanding of auto, you didn’t watch the video I linked or wasn’t capable of understanding it.

If you want to stick with C++98 why did you suggest moving to C++11?
Especially considering you don’t understand and like C++11.


#19

if f() return not int it should be fixed - “I need int, but it not, wtf” - auto hide this problem

auto isn’t about quick writing

auto not about quick learning unknown code

you didn’t watch the video

I can found 1000 links criticized auto

Herb Sutter (Microsoft)

I will not say anything about quality of code in Microsoft’s products xD


#20

Phew. If auto was long and complex, would anybody use it? I am sure no.
There are two groups of people who use auto: ones use auto because it is shorther, others don’t want to admit it and try to find another reasons. A kind of lying to yourself.

If that’s your understanding of auto, you didn’t watch the video I linked or wasn’t capable of understanding it.

If somebody change return type of function, he must revise all places where function is used just because they are affected by this change. Regardless of using or not using auto.

I didn’t watched the video because:

  • I’ve read Sutter and Co and know almost all this stuff about auto
  • Nobody explains how to solve readability issues except selfish phrases like >>you don’t need to know a type because I don’t<<
  • When project is big and maintained by many people, other pros and cons of auto are negilible comparing to readability problem

If you want to stick with C++98 why did you suggest moving to C++11?
Especially considering you don’t understand and like C++11.

С++11 has many cool features (including auto) but it doesn’t mean that they shall be thoughtlessly used everywhere.