4 ms·
> replace auto with explicit type declaration Hey, I am curious, when do I want to do that instead of relying on auto? Mostly curious, as I have been using aut
by a1o 3y ago
> replace auto with explicit type declaration
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.
- dataflow 3y agoPeople have different views on this. 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.
- fluoridation 3y agoOn the other hand, spelling out types tends to make refactors unnecessarily complicated. Something that could otherwise be simple, like moving a type from one scope to another, or changing the return type of a function for a different but compatible type, can require changing arbitrarily many usages.
- eliasmacpherson 3y agoThis refactoring business, I see it going two ways, there are probably more. 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.
- fluoridation 3y agoIf you're replacing types in this manner you don't scrutinize the usages. You design (or choose) the new type such that it actually is compatible with the old type. For example std::vector and std::list can be replaced with each other, because they either have the same functions with analogous behavior, or you get compiler errors if you use any of the non-overlapping functions. What you can't do is replace an std::vector with a class whose clear() fills the container with default-constructed instances of the objects. In other words, you concentrate your review on the original and new type, instead of the usages.
- eliasmacpherson 3y ago> You design (or choose) the new type such that it actually is compatible with the old type. 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?
- fluoridation 3y ago>the case can arise that a new type must no longer compatible with the old type 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.
- eliasmacpherson 3y ago
- dataflow 3y agoWhen you can use auto without hampering readability, and while improving maintainability, by all means do so. This is often the case when the actual type doesn't matter to the reader, for example. I basically said this in my earlier comment. 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.
- fluoridation 3y agoSure, but like I said in a sibling comment, I don't believe that knowing the types of the objects is actually helpful in understanding a piece of code. You'll need to know the actual types to know its exact performance characteristics, but if you can't understand what the code does even at a high level when you can't see any types then there's a problem anyway.
- dataflow 3y ago> but if you can't understand what the code does even at a high level when you can't see any types then there's a problem anyway. 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?
- fluoridation 3y agoNo, that the code is poorly documented, or that the names are poorly chosen.
- dataflow 3y agoSometimes, but not necessarily. Even when that's the case (and nobody always gets all the names perfect in the first iteration), you still face the problem of understanding it before you can fix that, so throwing your hands up is not a solution. Regardless, the rest of my comment stands.
- rudedogg 3y agoIt doesn't go very deep, but the Unreal Engine style guide has a section on auto: https://docs.unrealengine.com/5.2/en-US/epic-cplusplus-coding-standard-for-unreal-engine/#auto https://docs.unrealengine.com/5.2/en-US/epic-cplusplus-codin...
- OnionBlender 3y agoSome teams discourage it because it makes code reviews a little harder. I worked on a team that allowed it for obvious things like iterators or std::make_unique<>. From Google's C++ Style Guide: https://google.github.io/styleguide/cppguide.html#Type_deduction 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.
- dataflow 3y ago> Some teams discourage it because it makes code reviews a little harder 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.
- fotta 3y agoit's like trying to read untyped python code, which is my personal hell
- hardware2win 3y agoI do wonder, you arent using IDE?
- _aavaa_ 3y agoIn my experience even something like Pycharm can't inference types properly across function boundaries unless you explicitly provide type hints.
- jcranmer 3y agoIt generally tends to be in the case in large projects that having the type of every variable identified is useful. Projects that follow this rule generally restrict the use of auto to a) cases where it's necessary (lambdas), b) cases where the type is obvious but spelling it properly is annoying or difficult (e.g., x.begin()--it's an iterator, everyone should understand that, but what is the actual name of that iterator class?), and c) cases where the type is repeated (e.g., if (auto *SI = dyn_cast<StoreInst>(I)), a common pattern in LLVM).
- fluoridation 3y agoBeyond stylistic discussions that siblings have pointed out, there are cases where explicitly using a type instead of auto would be preferable given the semantics at that location. For example, you might want to force a type conversion where auto would otherwise give you a different or even unknown type (because the source type is templated).
- mrtracy 3y agoI recently learned that Godot forbids auto in its core C++ codebase, their rationale was based on code review: > 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/development/cpp_usage_guidelines.html#auto-keyword https://docs.Godotengine.org/en/stable/contributing/developm...
- vips7L 3y agoWe've taken this approach with var in Java. If we can't tell the type from the right hand side it should be declared on the left. var m = new Thing(); // you know its a thing var t = a.b().c(); // what is it?
- PaulDavisThe1st 3y agoin loops, the lack of knowing can be considered a positive though: 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".
- fluoridation 3y agoNaming issues aside, the type of t shouldn't matter, in the same way that the type of a.b() doesn't matter. What matters is how t relates to the code around it. What's the purpose of t in the context where it's used? What does it store? If you don't know whether t is an iterator over a sequence, the timestamp of an event, or the measurement of a sensor, knowing whether t is an int or a string won't help you much. If you do know that, knowing the specific type of t will probably not provide much more additional information, since in any given codebase for almost all non-primitive types there's at most two different types with comparable purpose.
- lern_too_spel 3y agoYou want types in a public API to be explicit, so you don't break it by accident.
- DrBazza 3y agoSometimes it just makes sense to explicitly type something so that a human can understand what is going on.
- david422 3y agoIntellij does a lot of smart stuff with their code - one thing I would like to see is "replace auto" but only on the visual overlay - much like they do with dynamic param types etc. That way you can visually see the type as you're working, but you can still just explicitly type "auto" if you wan.t