auto: useful, annoying or bad practice?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Wed May 9 12:44:34 UTC 2018


On Monday, April 30, 2018 21:11:07 Gerald via Digitalmars-d wrote:
> I'll freely admit I haven't put a ton of thought into this post
> (never a good start), however I'm genuinely curious what people's
> feeling are with regards to the auto keyword.
>
> Speaking for myself, I dislike the auto keyword. Some of this is
> because I have a preference for static languages and I find auto
> adds ambiguity with little benefit. Additionally, I find it
> annoying that the phobos documentation relies heavily on auto
> obscuring return types and making it a bit more difficult to
> follow what is happening which gives me a bad taste for it.
>
> Having said, the thing that really started my thinking about this
> was this post I made:
>
> https://forum.dlang.org/thread/fytefnejxqdgotjkprpo@forum.dlang.org
>
> Where in order to declare a public variable for the RedBlackTree
> lowerBound/upperBound methods I had to fall back on using the
> ReturnType template to declare a variable. Jonathan was nice
> enough to point me in the right direction and maybe there's a way
> to do this without having to fall back on ReturnType. However
> this made be wonder if reliance on auto could discourage API
> writers from having sane return types.
>
> So I'm curious, what's the consensus on auto?

I think that the overall consensus is that it's great but that you do have
to be careful about using it when it reduces clarity without adding other
benefits.

I remember when std.algorithm didn't use auto in any of its function
signatures, because there was a bug in ddoc that made it so that functions
that returned auto didn't show up in the docs. It was terrible. Seeing it
would have scared off _way_ more people than any concerns over auto returns
being confusing. You really, really, really don't want to know what many
auto return types look like - especially if ranges are involved. You end up
with templates wrapping templates, and seemingly simple stuff ends up
looking ugly fast - e.g. until returns something like Until!("a == b",
string, char). Having auto in the documentation is _must_ nicer.

Really, auto return functions make things possible that would never be
possible without it simply because the code would be too hard to read. In
the cases where all you care about is what API a return type has and not
what the return type is, auto is a true enabler. Voldemort types then take
than a step further by removing the possibility of referring to the type by
name and forcing you to go off of its API, which improves maintenance from
the perspective of the person maintaining the function (because then they
can change the return type as much as they like so long as its API is the
same). But even without Voldemort types, auto return types simplify the
information to remove all of that extra stuff that you don't care about the
type.

Of course, that can be taken too far and/or handled badly. The user of a
function doesn't necessary have to care what the return type is, but they
_do_ have to know enough to know what its API is. And that means that
whenever a function returns auto, it needs to be clear in its documentation
about what it's returning. If it's not, then obviously, the use auto becomes
a problem. At least an explicit return type would have then made it possible
for the user to look up the return type, whereas with auto and bad
documentation, they're forced to use stuff like typeof and pragma(msg, ...)
to figure out what the type is or to go look at the source code. So, while
auto is awesome, anyone writing such a function needs to do a good job with
documentation and try to put themselves in the shoes of whoever is using the
function.

Another thing that can be taken from that is that if a function is designed
to return something specific as opposed to an arbitrary type with a specific
API, then it's generally better to put the type in the signature so that
it's clear rather than use auto.

As for auto inside functions, I'd argue that it should be used heavily, and
I think that most of us do. The cases where there's really no debate are
functions that return auto, and when using the type's name would just be
duplicating information. e.g. it's just bad practice to do

Type foo = new Type(42);

instead of

auto foo = new Type(42);

Avoiding auto buys you nothing and just increases your code maintenance if
you change the type later. It's when you start using auto all over the place
that it gets more debatable. e.g.

auto foo = someFunc();
foo.doSomething();
auto bar = someOtherFunc(foo);

Depending on what the codes doing, heavy use of auto can sometimes make such
functions hard to read, and some common sense should be used. However, by
using auto, you're frequently making it easier to refactor code when types
change, as they sometimes do. In that snippet, so long as I can call
doSomething on foo (be it as a member function or via UFCS) and so long as
someOtherFunc accepts whatever type foo is, I don't necessarily care if the
type of foo changes. If I need to refactor someFunc so that it returns
something else that has a compatible API, then someFunc can be changed
without having to change the code using it, whereas if the type name had
been used explicitly, I would have had to change a lot more. And if the new
type doesn't have a compatible API, then it will fail to compile either way,
so the use of auto didn't matter.

The only real problem here is how readable the code is with auto, and that's
going to be very dependent on what the code is doing it and who is reading
it. But the types can still be figured out just by looking at the functions
being called (and if you're actually using an IDE like many us don't, then
you could probably hover your mouse over the type too see what it is without
even looking at the documentation for the function), and honestly, I would
argue that if you don't know what the functions being called are doing, then
you need to look them up anyway. And if you do know what they're doing, then
you know what they're returning, and auto isn't a problem at all.

Really, if it becomes a readability problem, then use explicit types, but in
general, I think that using auto ultimately makes the code more
maintainable, much as it can take some getting used to.

And I think that the biggest problems with using auto simply come from not
being used to it and not knowing how to deal with it in those annoying cases
where you need an explicit type but don't have one (e.g. to declare a member
variable which isn't directly initialized) - but even that is really more of
an issue with Voldemort types than auto specifically (much as they're
related).

I think that experienced D programmers tend to use auto pretty much
everywhere inside of functions and only use explicit types where necessary.
The bigger question is when to return auto or not, and as long as the
documentation is solid, that's usually not a problem - though if using auto
isn't going to buy you anything there, then you might as well make the type
explicit, since that improves clarity and simplifies the documentation.

- Jonathan M Davis



More information about the Digitalmars-d mailing list