Hey, I am curious, when do I want to do that instead of relying on auto? Mostly curious, as I have been using auto in C++ (since C++11) relatively heavily.
Hey, I am curious, when do I want to do that instead of relying on auto? Mostly curious, as I have been using auto in C++ (since C++11) relatively heavily.
From Google's C++ Style Guide:
https://google.github.io/styleguide/cppguide.html#Type_deduc...
> The fundamental rule is: use type deduction only to make the code clearer or safer, and do not use it merely to avoid the inconvenience of writing an explicit type. When judging whether the code is clearer, keep in mind that your readers are not necessarily on your team, or familiar with your project, so types that you and your reviewer experience as unnecessary clutter will very often provide useful information to others. For example, you can assume that the return type of make_unique<Foo>() is obvious, but the return type of MyWidgetFactory() probably isn't.
I would typically use auto while working on something but then have to replace many of them before creating a code review. I wish Visual Studio could do that, it clearly already knows the type.
Not just reviews, but anything that involves reading the code (which is frequently usage and maintenance). Swimming in a file where everything is auto is a special kind of hell. It's like having no firm ground to step on.
I agree that if you spend a lot of time reading code in something like GitHub, not having explicit types is annoying, but seriously, who does that?
- No review tool is capable of providing type inference hints.
- Not everybody's development workflow consists of using the IDEs.
- Development/debugging on remote machines does not even have a GUI to start with - so no IDEs there as well.
It also makes it harder to grep for usages of any given type. Of course IDEs could help with that too, but I don’t know any that provide that functionality.
Can you compute elementary functions by hand? Why not? Why are you crippled without semiconductors? This attitude leads to never being able to use better tools. We can't leverage an IDE because then we're "crippled" when we don't have it, so we continue writing code as if it was the '70s and the best we have is ed.
I understand how type deduction works just fine, thank you. Your assumption that I (or many others) have this stance based on some lack of understanding of how type deduction works is extremely wrong, and completely missing the arguments people are actually making.
I wouldn't use it for my project or any new project. It's out of date with how everyone else codes C++.
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
Isn't the return type of a widget factory method obviously Widget? This doesn't seem like a great example. Of course the method name could be wrong and not enforced at the language level like something between angle brackets, but idk.
My take is: if the code is type-agnostic (i.e. should remain identical when the type changes), and writing the type wouldn't help the reader, and the type itself isn't already a simple-to-write template (like T), then use auto. (For example, this is the case when you're just taking some value and passing it along, and have no reason to care about the type at all.) Otherwise, write it out.
The intent being that you should prefer to spell out the type unless it's genuinely adding a burden (such as being difficult to read, or adding an extra location to update if it ever changes) when the benefits are also negligible, because it's frequently useful information and a good sanity check.
1. you refactor, you change the type declaration in one place, auto handles the boring work of replacing the characters throughout your project.
2. you refactor, you change the type definition in one place, auto will handle replacing all the instances in your project, hell, it might even compile afterwards.
I believe you are describing 1. I find that easy enough to do with 'Sed' or IDE refactoring tools.
2, is more subtle and the new behaviour could now be worthy of scrutiny throughout the project. I find it difficult then to 'Grep' or IDE search through the project for all instances reliably when auto is in use. It is much easier for me with spelled out types.
I would trade the benefit of auto in 1) for the safety of spelled out types in 2) every single time.
In other words, you concentrate your review on the original and new type, instead of the usages.
Yes I agree, in that case sure, but when refactoring the case can arise that a new type must no longer compatible with the old type, then auto becomes a hindrance.
std::vector and std::list have different behaviour regarding the validity of iterators after deletion (EDIT: and insertion so it seems!), to pick an example.
Maybe I'm just paranoid?
Then you make sure that whatever causes an incompatibility also causes a compilation error. You can't rely on text searches and IDEs for something like that.
>std::vector and std::list have different behaviour regarding the validity of iterators after deletion
Fair enough, perhaps not the best-chosen example. I was thinking about them purely as collections, rather than as part of resource management. Checking their behavior with automated tools becomes much more difficult once people start taking pointers into elements. But then again, that's true of any class. If, for example, a member function returns a reference to a member and someone gets its address, now that location is implicitly relying on the internal stability of the class in a way that's invisible to the type system.
Hm... Hypothetically, with a lot of effort you could design a dummy class (A) that implements only the members you want to investigate and where necessary returns a different dummy class (B) representing the element type. If someone ever tries to take the address of a B (you have to delete operator&() and/or get() if it's some kind of smart pointer) then you know you might be dealing with iterator invalidation.
The iterator invalidation occurs when push_back(), insert() or erase() are called, presumably among others, so you'd also want to overload the iterator increment and decrement operators too (oh!, not to forget end(), or rend() if you are going the other way...). I'm not sure what operators and methods would be called on passing to an std::algorithm like std::find or std::sort. Most likely the only way to find out for certain would be to make everything inaccessible and replace piecemeal until the compiler was happy to run to completion.
I'd want to take a closer look where it's instantiated, but if all the uses are 'auto', well let's just say I'd be unhappy to say the least.
But that's second priority to readability, because people read code much more often than they refactor it, and they need to be able to easily anchor their understanding when reading. Optimizing code for efficiency of editing instead of the ability to understand it is getting the priorities very wrong.
Who says this implies you can't understand what the code does at a high level? Often you know the high level behavior but need to figure out how it works so you can update the code. If anything, the high level behavior is often easier to understand, since you have the API documentation etc. available.
And in the cases where that is the case, what does "there's a problem anyway" mean? That the reader is too stupid to figure it out?
Regardless, the rest of my comment stands.
> Keep in mind hover documentation often isn't readily available for pull request reviewers. Most of the time, reviewers will use GitHub's online viewer to review pull requests.
`using` directives and typedefs are not forbidden, so this would avoid situations where a type is never explicitly declared.
Having worked in large code bases that used `auto` almost exclusively when possible… I’m not sure I agree. However, I understand.
https://docs.Godotengine.org/en/stable/contributing/developm...
var m = new Thing(); // you know its a thing
var t = a.b().c(); // what is it? for (auto const & thing : container_of_things) {
thing->method ();
}
in this context (and this context alone) i love not knowing or having to explicit denote the type of "thing". var t = a.b().c(); // what is it?
Most likely bad code (on the right hand side)