103

Possible Duplicate:
How much is too much with C++0x auto keyword

Have we (as a community) had enough experience to determine when and/or whether auto is being abused?

What I am really looking for is a best practices guide on

  • when to use auto
  • when it should be avoided

Simple rules of thumb that can quickly be followed in 80% of cases.

As a context this question is sparked by my response here

Community
  • 1
  • 1
Martin York
  • 234,851
  • 74
  • 306
  • 532
  • 10
    auto keyword for sure reduces readability of the code. – Arunmu Aug 01 '11 at 15:21
  • 1
    @UncleBens I don't think that looks bad at all. The template type argument to `static_cast` immediately conveys what type `m` is, so it is very readable. IMO, abuse is in cases where you use `auto` to deduce the types of return values for user defined functions. – Praetorian Aug 01 '11 at 15:23
  • 1
    @Praetorian I disagree, `auto` in these circumstances reduces conversions and dependencies. If it's not important that a value has any *particular* type, only that it has the correct one, then use `auto` liberally! – spraff Aug 01 '11 at 15:34
  • It's been discussed already here: http://stackoverflow.com/questions/6434971/how-much-is-too-much-with-c0x-auto-keyword/6435066#6435066 – Gene Bushuyev Aug 01 '11 at 16:28
  • `auto` does not declare "variable type"s – Lightness Races in Orbit Aug 31 '11 at 12:58

6 Answers6

162

I think when the type is very well-known amongst the co-programmers who work (or would work) in your project, then auto can be used, such as in the following code:

//good : auto increases readability here
for(auto it = v.begin(); it != v.end(); ++it) //v is some [std] container
{
      //..
}

Or, more generally,

//good : auto increases readability here
for(auto it = std::begin(v); it != std::end(v); ++it)//v could be array as well
{
      //..
}

But when the type is not very well-known and infrequently used , then I think auto seems to reduce readability, such as here:

//bad : auto decreases readability here
auto obj = ProcessData(someVariables);

While in the former case, the usage of auto seems very good and doesn't reduce readability, and therefore, can be used extensively, but in the latter case, it reduces readabilty and hence shouldn't be used.


Another place where auto can be used is when you use new1 or make_* functions , such as here:

//without auto. Not that good, looks cumbersome
SomeType<OtherType>::SomeOtherType * obj1 = new SomeType<OtherType>::SomeOtherType();
std::shared_ptr<XyzType> obj2 = std::make_shared<XyzType>(args...);
std::unique_ptr<XyzType> obj2 = std::make_unique<XyzType>(args...);

//With auto. good : auto increases readability here
auto obj1 = new SomeType<OtherType>::SomeOtherType();
auto obj2 = std::make_shared<XyzType>(args...);
auto obj3 = std::make_unique<XyzType>(args...);

Here it is very good, as it reduces the use of keyboard, without reducing the readability, as anyone can know the type of objects being created, just by looking at the code.

1. Avoid using new and raw-pointers though.


Sometime, the type is so irrelevant that the knowledge of the type is not even needed, such as in expression template; in fact, practically it is impossible to write the type (correctly), in such cases auto is a relief for programmers. I've written expression template library which can be used as:

foam::composition::expression<int> x;

auto s = x * x;       //square
auto c = x * x * x;   //cube
for(int i = 0; i < 5 ; i++ )
    std::cout << s(i) << ", " << c(i) << std::endl; 

Output:

0, 0
1, 1
4, 8
9, 27
16, 64

Now compare the above code with the following equivalent code which doesn't use auto:

foam::composition::expression<int> x;

//scroll horizontally to see the complete type!!
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply>> s = x * x; //square
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply> >, foam::composition::expression<int>, foam::operators::multiply>> c = x * x * x; //cube

for(int i = 0; i < 5 ; i++ )
    std::cout << s(i) << ", " << c(i) << std::endl; 

As you can see, in such cases auto makes your life exponentially easier. The expressions used above are very simple; think about the type of some more complex expressions:

auto a = x * x - 4 * x + 4; 
auto b = x * (x + 10) / ( x * x+ 12 );
auto c = (x ^ 4 + x ^ 3 + x ^ 2 + x + 100 ) / ( x ^ 2 + 10 );

The type of such expressions would be even more huge and ugly, but thanks to auto, we now can let the compiler infer the type of the expressions.


So the bottomline is: the keyword auto might increase or decrease clarity and readability of your code, depending on the context. If the context makes it clear what type it is, or at least how it should be used (in case of standard container iterator) or the knowledge of the actual type is not even needed (such as in expression templates), then auto should be used, and if the context doesn't make it clear and isn't very common (such as the second case above), then it should better be avoided.

Nawaz
  • 327,095
  • 105
  • 629
  • 812
  • 1
    In your first example. I think I would only use that within the context of a for loop `for(auto it = v.begin(); it != v.end(); ++it) {}` – Martin York Aug 01 '11 at 15:23
  • @LokiAstari: Added the examples of expression templates. See them. :-) – Nawaz Feb 24 '13 at 07:04
  • 2
    This is the type of answers that make *stackoverflow* my first goto reference – andresgongora Oct 14 '16 at 10:18
  • There is a typo here (copy-pasted as-is): `SomeType::SomeOtherType pObject = new SomeType::SomeOtherType();` --> There should be an asterisk before `pObject` – Happy Green Kid Naps Dec 30 '16 at 02:30
  • "//bad : auto decreases readability here auto obj = ProcessData(someVariables);" -- No, it's not `auto` that decreases readability, it's `obj` and `ProcessData`, in place of names with semantic content. This is so obvious, and so fundamental to one's understanding of programming, that I reject all interviewees who don't grasp it. – Jim Balter Jan 26 '17 at 01:23
  • @JimBalter: I partly agree with that. But I meant `ProcessData` to be a function which is not well-known to even *experienced* C++ programmers, because it is something very application-specific or so. For example, `auto it = x.begin();` seems to be comparably more readable. Why? Because `begin()` is a well-known function; any C++ developer who is aware with the standard library, would make a **reasonable** guess that `x` is some container/range (even user-defined container/range) and `begin()` returns the *begin* iterator with semantics `++it` and `*it`... (contd). – Nawaz Jan 26 '17 at 17:41
  • ... (contd) Now compare it with `auto it = y.Begin();` How comfortable are you to make a guess that `y` is a container/range and `i` is an iterator which supports `++it` and `*it`, not `it.Next()` and `it.Value()`? I hope you now understand the argument. – Nawaz Jan 26 '17 at 17:41
  • 3
    I know this is 6 years old, but I still laughed out loud at your square/cube example. Getting back into c++ since 1997 and c++11(14) is delightful. – PeterT May 15 '17 at 15:37
  • @PeterT: Why laughed out loud? You didn't like the example? Doesn't it illustrate what I'm trying to say? – Nawaz May 15 '17 at 18:23
  • 1
    @Nawaz Just the opposite, it is a fantastic example. It shows how C++ syntax is really ugly sometimes, and how auto simplifies readability. – PeterT May 16 '17 at 19:31
21

Easy. Use it when you don't care what the type is. For example

for (auto i : some_container) {
   ...

All I care about here is that i is whatever's in the container.

It's a bit like typedefs.

typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;

Here, I don't care whether h and w are floats or doubles, only that they are whatever type is suitable to express heights and weights.

Or consider

for (auto i = some_container .begin (); ...

Here all I care about is that it's a suitable iterator, supporting operator++(), it's kind of like duck typing in this respect.

Also the type of lambdas can't be spelled, so auto f = []... is good style. The alternative is casting to std::function but that comes with overhead.

I can't really conceive of an "abuse" of auto. The closest I can imagine is depriving yourself of an explicit conversion to some significant type -- but you wouldn't use auto for that, you'd construct an object of the desired type.

If you can remove some redundancy in your code without introducing side effects, then it must be good to do so.

spraff
  • 29,265
  • 19
  • 105
  • 197
17

I’d apply the same rule as for var in C#: use it liberally. It increases readability. Unless the type of a variable is actually important enough to be stated explicitly, in which cases this should be done (duh).

Still, I maintain that (especially in statically typed languages) the compiler is much better at tracking types for us than we are. Most of the time, the exact type isn’t terribly important anyway (otherwise interfaces wouldn’t work in practice). It’s more important to be aware of which operations are permitted. Context should tell us that.

Furthermore, auto can actually prevent bugs, by preventing unwanted implicit conversions in initialisations. Generally, the statement Foo x = y; will perform an implicit conversion if y isn’t of type Foo and an implicit conversion exists. This is the reason to avoid having implicit conversions in the first place. Unfortunately, C++ has much too many of them already.

Writing auto x = y; will prevent this problem in principle.

On the other hand, it should be clear that when I’m performing calculations that assume this or that number of bytes in an integer, the explicit type of the variable must be known and should be clearly stated.

Not all cases are as clear cut but I maintain that most are, and that

  1. in most cases it’s easy to see whether an explicit type needs to be known, and
  2. the need for explicit types is comparatively rare.

Eric Lippert, principal developer on the C# compiler team, has stated much the same with regards to var.

Community
  • 1
  • 1
Konrad Rudolph
  • 482,603
  • 120
  • 884
  • 1,141
  • 2
    *`auto` can actually prevent bugs, by preventing unwanted implicit conversions* -- Just as easily it can introduce bugs, when implicit conversions are actually *wanted* – Gene Bushuyev Aug 01 '11 at 16:52
  • 7
    @Gene Please, but that’s just implausible. If you *want* the conversion, you use it. If you write `auto` you clearly don’t expect any conversion to take place. – Konrad Rudolph Aug 01 '11 at 17:51
  • @ Konrad: don't you find it funny that you advocate `auto` which states user intent implicitly to avoid the danger of implicit conversions. – Gene Bushuyev Aug 01 '11 at 17:56
  • 1
    I am not sure I buy your arguments yet (still thinking about it). But do you think the extensive use of auto helps the readability of the code? In my opinion maintenance of code goes on for much longer than development as such readability for the next person is paramount. – Martin York Aug 01 '11 at 18:00
  • 5
    @Gene No. The two have nothing to do with each other. The danger that implicit conversions have simply isn’t present in implicit typing of variables. Implicit conversions are problematic *only because* they hide a semantic action that may not be intended. `auto` does no such thing. – Konrad Rudolph Aug 01 '11 at 18:01
  • 1
    @Martin It helps readability in those cases where the type is irrelevant or has a convoluted name (or both). In many other cases it just does no harm. Best case, it hides an irrelevant detail. This *does* increase readability quite substantially. – Konrad Rudolph Aug 01 '11 at 18:03
  • @ Konrad: *The danger that implicit conversions have simply isn’t present in implicit typing of variables.* -- See the answer by Jerry Coffin above. And yes, there are definite similarities between `auto` and other implicit language constructs; when you don't tell the compiler explicitly what you want, its decisions may disagree with your assumptions. The code that doesn't make gratuitous assumptions is easier to read and more robust. – Gene Bushuyev Aug 01 '11 at 19:04
  • @Gene Can you be more precise? I can’t see anything in Jerry’s answer that relates to this. About assumptions: my point in using `auto` is to drop gratuitous assumptions. Necessary assumptions should of course be made explicit but my point is exactly that those are pretty rare. – Konrad Rudolph Aug 01 '11 at 19:11
  • The only counter-example I can think of where you might *lose* implicit conversions you were expecting is if someone takes a chunk of legacy code and does a MAR (Massive `auto` replacement) without proper analysis. So... don't do that, I guess. – deworde Feb 22 '16 at 10:01
5

I think the answer to your first question is sort of no. We know enough to put together some guidelines about when to use or avoid auto, but they still leave quite a few cases where the best we can currently say is that we can't yet give much in the way of objective advice about them.

The obvious case where you nearly have to use it is in a template when you want (for example) the proper type to hold the result of some operation on two generic parameters. In a case like this, the only possibility of abuse wouldn't really be abuse of auto itself, but whether the general type of operation you're doing (or type of template you're writing, etc.) is something you'd be better off avoiding.

There are also at least a few situations where you clearly need to avoid auto. If you're using something like a proxy type where you're depending on the conversion from proxy->target to do part of the job at hand, auto will (attempt to) create a target of the same type as the source so that conversion won't happen. In some cases, that may just delay the conversion, but in others it won't work at all (e.g., if the proxy type doesn't support assignment, which is often the case).

Another example would be when you need to assure that a particular variable has a specific type for the sake of something like an external interface. Just for example, consider applying the network mask to an IP (v4) address. For the sake of argument, let's assume you're working with the individual octets of the address (e.g., representing each as an unsigned char), so we end up with something like octets[0] & mask[0]. Thanks to C's type promotion rules, even if both operands are unsigned chars, the result is typically going to be int. We need the result to be an unsigned char though (i.e., one octet) not an int (typically 4 octets) though. As such, in this situation, auto would almost certainly be inappropriate.

That still leaves a lot of cases where it's a judgement call though. My own tendency for these cases is to treat auto as the default, and only use an explicit type in cases that are at least a little like the latter case I've cited above -- even if a particular type isn't needed for correct operation that I really want a particular type, even if that might involve an implicit conversion.

My guess (but it is just a guess) is that over time, I'll probably tend even more in that direction. As I get more accustomed to the compiler picking out types, I'll find that a fair number of cases where I currently think I should specify the type, I really don't need to and the code will be just fine.

I suspect a lot of us (and the older/more experienced we are, probably the worse we'll be about it) will use explicit types for reasons that ultimately trace back to some feeling about performance, and believing that our choice will improve performance. Part of the time we may even be right -- but as most of us with that much experience have found, our guesses are often wrong (especially when they're based on implicit assumptions), and compilers and processors generally get better at such things over time as well.

Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035
  • It sounds very reasonable. I also think a lot of us *(and the older/more experienced we are)* when writing code know **exactly** the types we need use (except the cases you specified), so using `auto` instead of explicit type would require in some cases more mental work to prove to oneself that it's the same. Being explicit with compiler is not a bad thing. Maybe with time that burden of using `auto` will go away. – Gene Bushuyev Aug 01 '11 at 17:06
  • I like the fact that you think older people are less flexible :-) I remember when we switched from ` – Martin York Aug 01 '11 at 18:04
2

Only use it with long repetitive types such as long templates and lambda function types. Try to avoid it if you can to make things clear.

user32434999
  • 4,176
  • 18
  • 46
Will03uk
  • 3,086
  • 6
  • 30
  • 37
2

I've used languages with full type inference. I see no reason not to put auto everywhere it's technically possible*. In fact I may have already written auto i = 0;, where int is one character shorter than auto. I'm not even sure that I did because the bottom is: I don't care for manifest typing.

*: for instance auto int[] = { 0, 1, 2, 3 } doesn't work.

Luc Danton
  • 33,152
  • 5
  • 66
  • 110
  • 4
    It doesn't matter for compiler, but it can matter for the reader. Whenever `auto` hurts the readability it should be avoided. – Gene Bushuyev Aug 01 '11 at 16:31
  • 2
    @Gene That amounts to a tautology; the question is *whether* (or when) `auto` hurts readability. – Konrad Rudolph Aug 01 '11 at 16:35
  • 3
    @Gene I understand that. My position is simply that `auto` never hurts readability. I have clarified some ambiguous wording in my answer. – Luc Danton Aug 01 '11 at 16:38
  • 1
    @Konrad: tautology is not always bad in human interactions, it's often recommended as a way to make things clear to the reader. – Gene Bushuyev Aug 01 '11 at 16:44
  • @Luc: I think it does (http://stackoverflow.com/questions/6434971/how-much-is-too-much-with-c0x-auto-keyword/6435066#6435066). But since readability is quite subjective and some people claim that `r_and_t&, r_char_t&>, r_char_t&>` is quite readable, I won't go into that subject any further. – Gene Bushuyev Aug 01 '11 at 16:46