2

In C++, the auto keyword forces the compiler to deduce a variable's type at compile time. So in this example

#include <vector>
int main() 
{
  std::vector<int> my_vec = {1, 2, 3};
  auto my_vec_it = my_vec.begin();
  return 0;
}

the compiler would deduce that my_vec_it has type std::vector<int>::iterator. I know this because replacing auto with std::vector<int>::iterator and recompiling produces the exact same executable.

I've found auto to be handy in situations where the compiler doesn't agree with what I think a variable declaration should be, and I just want it to stop complaining so I can keep writing. In other words, I use auto when I don't really understand the code I'm writing, and that seems like a bad habit. If the compiler and I disagree on a variable's type, that disagreement could percolate and cause more complicated, deeply-rooted errors further down in my code. That makes me wonder what the use auto really is.

Is the use of auto I describe above a bad programming practice, and if so what are some more principled uses of it?

  • If the proper variable type is that hard to determine, then yes, you probably shouldn't use `auto`. – HolyBlackCat Jul 24 '20 at 17:48
  • 1
    It isn't bad programming practice. But, remember do you value writability over readability? or vice versa. I personally think readability is more valuable in the long run to help a developer read the code much more easier and understand what is happpening. Remember we don't want to make C++ into Python! It's also hard to read in C++ when you are trying to assign it to some inherited class or something, and if it is used all throughout it's very hard to read and understand what class is being instantiated and what not. I would lean towards creating #define/typedef's for easier readability – Omid CompSCI Jul 24 '20 at 17:48
  • 1
    The fact that you can name a variable in a useless manner facilitates sloppy programming. If you're using `auto` without understanding what's going on, the variable name will surely be horrible. – chris Jul 24 '20 at 17:52
  • 1
    Using `auto` or explicitly spelling out the type (*usually*) results in the exact same thing. `auto` is not a type itself, it's just a keyword telling the compiler "please deduce the correct type here so I don't have to spell it out". The end result is (*usually*) the same. The reason I say *usually* is that in some cases implicit conversions may change things in ways that actually matter. – Jesper Juhl Jul 24 '20 at 17:56
  • 5
    How many times do you want to write `std::unordered_map, std::hash, std::equal_to, my_custom_allocator>>>::iterator`??? – user253751 Jul 24 '20 at 17:58
  • Here's a free hint: whenever the compiler "thinks you have the wrong type", use `auto`, then put `decltype(the_variable)::blah blah;` on the next line. The compiler will generate an error message saying the type has no member "blah" on it, but the error message will also tell you what the type was! – user253751 Jul 24 '20 at 18:00
  • Use auto when type is hard to write or hard to deduce from an initializer. – Ron Jul 24 '20 at 18:07
  • 1
    @user253751 Is writing long variable declarations more annoying or time-consuming than debugging weird compiler errors because your objects aren't quite what you think they are? I don't think so. – Dimitrije Kostic Jul 24 '20 at 18:14
  • 1
    @DimitrijeKostic You're not going to spot the difference between `std::unordered_map, std::hash, std::equal_to, my_custom_allocator>>>::iterator` and `std::unordered_map, std::hash, std::equal_to, my_other_custom_allocator>>>::iterator` anyway. But you could use `decltype(the_map)::iterator` – user253751 Jul 24 '20 at 18:18
  • @user253751 I may not be able to spot the difference (I'm not a power C++ user) but I'll bet my bottom dollar the compiler sees a difference. You can sidestep the problem of writing all that out repeatedly by just `typedef`ing it to something more reasonable. – Dimitrije Kostic Jul 24 '20 at 18:24
  • @Ron That comment from Stroustrup kind of goes right to the point I was trying to make, though. 'The type is hard to write' seems like a polite way of saying 'I'm lazy', and 'the type is hard to deduce from the initializer' is a polite way of saying 'I kind of don't know what I'm doing.' And it seems like the `auto` keyword is just enabling bad programming practice. – Dimitrije Kostic Jul 24 '20 at 18:28
  • 1
    LOL at people who are saying if you want to write out long datatypes and stuff. thats why you have TYPEDEF's or #DEFINES so something like std::unique_ptr can be written as #define std::unique_ptr ClassAUP... etc... – Omid CompSCI Jul 24 '20 at 18:33
  • 2
    @OmidCompSCI No. That's not at all what people are saying, and *please* don't use macros - *ever*. – Jesper Juhl Jul 24 '20 at 18:38

1 Answers1

7

Is the use of auto I describe above a bad programming practice

Yes. What makes it a bad practice is this part: I don't really understand the code I'm writing. To fix this practice, you need to have the self discipline to stop and study the program until you understand what you've written. auto may make programming easier and more convenient, but it is only tangentially related to the bad practice.

Note that understanding the program on an abstract level is in most cases sufficient. One doesn't need to (and practically cannot) know every detail at all times. For example, about auto my_vec_it = my_vec.begin();, it is mostly sufficient to know that my_vec_it is an iterator. For a bit more detail, one might be more precise and conclude that it is a random access iterator. Rest of the understanding comes from the knowledge of what an iterator is and how they can be used. There is no need to know the definition of that iterator type, nor even to know the name of that type.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • In my example, I could have assumed that the compiler would make `my_vec_it` a variable of type `std::vector::const_iterator`. Making that substitution also yields code that compiles, and I still understand that the variable is an iterator. But that little difference could create problems later. So it just seems like using `auto` creates room for ambiguity. – Dimitrije Kostic Jul 24 '20 at 18:18
  • Yes, I agree. Same nonesense as nullptr. Compatible to everything . . . – A M Jul 24 '20 at 18:23
  • @DimitrijeKostic How bad problems could a bad guess about constness of local variable's type really create? In many cases, it simply doesn't matter, and ability to not care about it is in that case a benefit. If you do encounter a problem, the fix is simple. "`begin` conventionally returns a non-const interator on a non-const subject" is certainly a good thing to learn, but the program that you're writing is not solely responsible for teaching you. That's what documentation and books are for. – eerorika Jul 24 '20 at 18:27
  • @eerorika The constness of an iterator can lead to compiler errors, but you're right that they're not terribly hard to solve. The situations I'm more concerned about are when the data types are more complicated, like the kind that @user253751 gave. If I know what data type the compiler is going to `auto`-generate, then explicitly using it seems like a good way to avoid ambiguity. And if I don't know what the data type will be, then I'm using `auto` in a bad way. In either case, what's the point of the keyword? – Dimitrije Kostic Jul 24 '20 at 18:35