Almost Always Auto Advocates Advise Automatic Application

The idea of almost-always-auto has been around for a few years and has fairly divided the C++ community. The effective result is that concrete types appear rarely in code, and variables are declared as ‘auto’ instead.

Some of the reasons to use auto include

It’s correct – No accidental type conversions

It’s general – Hiding types encourages easier maintenance

It’s quieter – Less type noise is higher readability

It’s safe – You can’t forget to initialize it

I implemented an automated clang-based tool to port an existing codebase to use auto extensively, and I used it to automate the port of Qt.

Assessing Approved Alternative Alias

In applying these rules by default, declarations which break the rule stand out much more. The reason for non-use of auto could be type conversion, which may be accidental or deliberate. That can lead a human to assess why the rule was broken and perhaps make the code more explicit about that.

Advocates of using AAA suggest using auto by default everywhere it can be used. This results in the type being on the right hand side instead of the left side most of the time where it is written explicitly at all.

auto myString = getSomeString(); auto myDateTime = QDateTime{}; auto myWidget = static_cast<QWidget*>(getTabWidget());

Declarations which follow the AAA rules are much more uniform with each other as a result.

Part of the appeal is that it compares well with the cxx_alias_templates feature, which also puts the name on the left and the type on the right.

using GoodContainer = std::vector<int>;

One measure of maintainability is the amount of code which needs to be ported when something incidental changes. If we change a function return type, without changing how that return value is used, then client code does not need to be ported if we use auto. That is:

auto someWidget = someFunc(); // Returns Widget* someWidget->use();

does not change, but remains:

auto someWidget = someFunc(); // Now returns unique_ptr! someWidget->use();

under maintenance.

Axiom Awakens Alarmist Aversion

Of course, not everyone likes the AAA style, citing concerns such as needing to see the type in the code for readability and maintenance.

Hawk-eyed readers will recognize that ‘readability and maintenance’ is both a reason to use auto and a reason not to use auto.

I can only offer the tautology that people who think using auto does not make sense will not see any sense in using auto.

Ableton Applies Agreeable Advisories

For code that we write where I work, we take something of an almost-AAA approach, using auto everywhere that an = sign appears. So, we’re likely to write

auto s1 = getString(); QString s2;

instead of

auto s1 = getString(); auto s2 = QString{};

although I could imagine that changing some day.

Nevertheless, that is where I have had most of my exposure to extensive use of auto by default. I liked it so must that I wanted to apply it everywhere.

Obviously I didn’t want to do such porting by hand (that would be likely to introduce bugs for one thing), so I looked for automated tools.

Accumulate Adjustments; Applying Acrobatics

The clang tidy tool only converts the most trivial of declarations. For a Qt developer, the only effect it has is to convert use of new to assign to an auto variable of the same type.

So

QTabWidget* tabWidget = new QTabWidget; QString s = getString(); int i = 7; QVector<int>::const_iterator it = someVec.begin(); QStringList sl = getStringList(); QStringList middleStrings = sl.mid(1, 500);

will get converted to

auto tabWidget = new QTabWidget; QString s = getString(); int i = 7; QVector<int>::const_iterator it = someVec.begin(); QStringList sl = getStringList(); QStringList middleStrings = sl.mid(1, 500);

Qt containers, iterators and value types are not converted at all.

This is far too conservative for an advocate of auto.

So, I decided to create my own auto-modernizer. I thought about adding it to the clang-tidy tool, however that does not build standalone. Instead it requires to be built as part of llvm and clang, making it too inconvenient at this point in development.

Instead I based my tool on the excellent clazy from Sergio. That allows me to emit warnings where auto can be used, and FIX-ITs to automatically change the code. The unit tests showing before and after are most illustrative of what the tool does, to wit:

auto tabWidget = new QTabWidget; auto s = getString(); auto i = 7; auto it = someVec.begin(); auto sl = getStringList(); QStringList middleStrings = sl.mid(1, 500);

All opportunities to port to auto are taken, such that any remaining types in the code are the ones which stand out while reading.

The last line was not changed – do you know why? It is not a bug in the tool.

Adherence Abounds, Absent Accidents

I wrote the tool while at the same time using it on Grantlee to port those libraries to an AAA style. This was very helpful in finding edge cases, and for learning a lot about the clang tooling API, which is very difficult for a newcomer.

I also used the tool to port Qt to AAA, which again helped iron out some bugs in the tool, and in my understanding of C++. Qt is not likely to make such heavy use of AAA, but it is useful for the port to exist for the purpose of discussion of what AAA really looks like at that scale.

After those exercises the tool seems to cover a good deal of typical Qt code.

The tool is safe for use with QStrings and the QStringBuilder expression template – it won’t replace a QString which triggers a conversion from QStringBuilder with a use of auto. It only ports declarations for which the type of the left hand side matches the type of the right hand side without conversion.

It can even issue warnings for locations where the tool is not able to introduce use of auto, for example because multiple different types are declared at once (and/or implicitly converted).

Apologies About Artistic Alliteration

I realize I’m breaking a sensible rule, but sometimes opportunities are too tempting!

Share this: Email

Like this: Like Loading... Related