Aaargh! AAA – Right Good and Hygenic

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!

12 Responses to “Aaargh! AAA – Right Good and Hygenic”

  1. Links 20/3/2016: Clair 1.0, UbuntuBSD | Techrights Says:

    […] Aaargh! AAA – Right Good and Hygenic […]

  2. Ivan Čukić Says:

    Very nice! There is one addition that would be benefitial – adding const as well for the things that do not get mutated in the method, and are not returned from the method (not to kill the RVO)

  3. steveire Says:

    Thanks!

    I agree that adding const where it can be added would be a good thing, but it is completely orthogonal to using auto.

  4. Ivan Čukić Says:

    I know🙂

  5. Gunnar Roth Says:

    1. Did I miss the link to this fine tool ? Or is it not publicly available?
    2. The link for “QString which triggers a conversion from QStringBuilder” goes to a 404 error page.

  6. Roland Leißa Says:

    I’m also more in the camp of using auto everywhere. However, there are some caveats:
    1) const – as Ivan pointed out.
    2) really dangerous:
    auto foo = f();
    will get you a copy – even if f() returns T&. This is clearly a flaw in C++11 and I don’t see why the standard committee came up with this behavior of auto. C++14 fixes this with the ugly decltype(auto). See https://en.wikipedia.org/wiki/C%2B%2B14#Alternate_type_deduction_on_declaration

  7. Chris Chittleborough Says:

    Awesome alliteration amazes!

  8. Sergey Vidyuk Says:

    using auto always in a language with nontrivial rules of automatic type conversion inherited from prestandard versions of C may make your life very unpredictable:
    http://stackoverflow.com/questions/30191924/why-auto-is-deduced-to-int-instead-of-uint16-t

  9. mydeveloperday Says:

    if using AAA is indeed the way to go, it makes me wonder why we even need to say the word “auto” at all..

    Surely c++ could be made to assume auto! auto just feels like superfluous text, its the argument against it that it doesn’t tell you the type, so why not get rid of it completely? After all hasn’t the for loop syntax been changed to handle

    for( e : c){
    }

    why could we not simply remove auto everywhere?

    myString = getSomeString();
    myDateTime = QDateTime{};
    myWidget = static_cast(getTabWidget());

  10. Grantlee v5.1.0 (Codename Außen hart und innen ganz weich) now available | Steveire's Blog Says:

    […] Modernization […]

  11. Generating Python Bindings with Clang | Steveire's Blog Says:

    […] the correct shared libraries and generally figuring out what the end-goal looks like. Having used clang APIs before, and having some experience with CMake, I decided to see what I could do to […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: