Hacker News new | past | comments | ask | show | jobs | submit login

Using 'auto' for return types seems just awful to me. In the context of a collaborative project, I don't want to have to dig through the implementation of someone else's function just to figure out what type it returns. Having an explicit return type is a form of self-documenting code.



The primary use-case of auto returns is for templated functions where the return type depends on the thing passed in. For example, in C++11 you have to write things like the following:

    template<typename Range>
    auto begin(Range& r) -> decltype(r.begin()) {
        return r.begin();
    }
The return type can't be specified by the function[0], and you have to copy and paste the body of the function into the decltype() clause to tell the compiler that the return type is whatever the thing it's wrapping returns. When you have some long and complicated expression rather than just r.begin() in the body, this duplication becomes a major issue.

[0] In this specific case you could require that Range have an iterator typedef and return that, but that approach does not generalize.


C++ templates used to be the most unreadable code this side of Perl, but with auto and a little documentation you can figure out what's happening fairly easily. Templates (and auto) are typically used when dealing with core libraries and should be documented better than average code anyway.

If someone starts using auto for every variable or returning it from every method, then they need a stern talking-to.


If there is a feature that could be misused, it will be misused.

It does not matter what the rationale behind the committee's decision was. This is standard practice in duck typed languages, and it will be adopted as well in C++, since it will be (imho, correctly) perceived as another step to bring C++ "to the 21th century".

You can stern-talk as much as you wish... but it won't have much effect unless backed up by an (effectively enforced) internal code style guide.

The barbarians are already at the gate. Which side are you going to pick?


> This is standard practice in duck typed languages

Only because there is no choice in those languages -- and, in those language communities, there's considerable call for finding a good way to include optional explicit and enforced declared typing specifically so that a choice does exist.

So, even given that communities that (unlike C++, even with auto existing) accept languages that don't provide an alternative to to the equivalent of "auto everywhere" push back against that practice to the extent of seeking language features to provide an alternative to it, I don't think that auto becoming an option is going to mean auto everywhere takes over C++.

There'll probably be some overuse (particularly in a brief period before a widely-accepted conventions on appropriate use are established), but its hardly the most dangerously abusable feature of the C/C++ language family.


If there is a feature that could be misused, it will be misused. It does not matter what the rationale behind the committee's decision was.

This is quite a narrow-minded line of thinking. You're saying "Feature X is should be excluded because of <possible consequence>". But we can say the converse about this same feature: "Feature Y should be included because <possible benefit>". Every programming language feature ever has had its pros and cons, and every language designer makes tradeoffs deciding which features to include and which to exclude.[1]

You also most likely overestimate the practical unreadability of the source code. IDEs are (or will be) smart enough to deduce and display the type of an auto declared variable[2] when you want it. For short functions, it will be blindingly obvious what the auto-declared return type of a function is. Using auto will vastly improve readability by reducing textual noise when a function returns (1) heavily templated expressions, (2) any type within a deeply-nested namespace, (3) any type with a long name, or especially (4) combinations of the previous three (e.g. std::vector::const_iterator< std::pair<std::string, double> >). Complicated types are a common issue in languages with static type systems[3].

I could go on. There are tons of use-cases where auto will help out. The biggest complaint I have is that you can auto-declare the return type of methods that return private variables from a class (unless I'm mistaken; I haven't actually tried it). This pokes leaky holes in your class's encapsulation, forming dependencies between external code and your class's private, internal implementation (although this may be possible through template magic...).

The barbarians are already at the gate. Which side are you going to pick?

Oh, cut the drama. Every language has some sort of a style guide, and C++ programmers are already used to following a style guide and programming with discipline. One more feature with a few downsides and a number of benefits is not going to make a difference, and is totally in line with its philosophy[1].

1: http://en.wikipedia.org/wiki/C%2B%2B#Philosophy 2: http://stackoverflow.com/q/19625115 3: https://github.com/rust-lang/rust/issues/10448


IDEs are (or will be) smart enough to deduce and display the type of an auto declared variable[2] when you want it.

Not to detract from your other points, but personally I wouldn't want to live in a world where my IDE is decided for me. A person sometimes has decades of experience with their text editor. Forcing them to use a different one just to do programming isn't necessarily the best idea.

Interesting question: Will the world benefit from a language that requires an IDE to program in? I can imagine how the answer might be "yes," but also other scenarios where it might be "no."


Perhaps I'm lucky, I haven't found internal coding styles to need _any_ enforcement, in my experience people find it inherently valuable.


Then start with Herb Sutter, because that is exactly his advice at the latest CppCon.


Yes, and he's said that in a few blog posts as well:

http://herbsutter.com/2013/06/07/gotw-92-solution-auto-varia...

http://herbsutter.com/2013/06/07/gotw-93-auto-variables-part...

http://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-...

He has some good points, but his perspective seems to be biased by a professional focus on writing libraries and more general-purpose code. He's also brilliant and can remember things like this:

  const int&  cir = val;
  auto        h   = cir;
  //The type of h is int.
It's difficult to make generic rules for how to use C++ (because it's used for everything from adware to nuclear reactors), but I can say that Herb's AAA (Almost Always Auto) rule would not fly on any development team I've ever worked with.


The type of h isn't so hard to understand, there. |auto| gives you a value; if you want a reference, use |auto&|. This rule actually makes |auto| more readable: you always know if you're looking at a reference or not.

Probably you expected |auto| to behave like |decltype()|, C++11's other form of type deduction, which gives you the actual type of an expression. C++14 adds |decltype(auto)|, which lets you declare local variables using this behavior if you want it.

I'm not sure whether I'd apply Herb's AAA rule quite as broadly as he suggests, but I think it's broadly right, because far too often in C++ we write a type twice on the same line, which is just redundant. I vastly prefer |auto val = new MyClass;| to |MyClass val = new MyClass;|, and similarly |auto casted = static_cast<MyType>(uncasted);| is completely readable without typing writing "MyType" a second time. C++ programmers are a conservative lot, but I expect using |auto| at least in those cases to be pretty mainstream within a few years.


That's a reasonable position, but the popularity of languages without any type declarations at all suggests that there are many people who don't mind. (python, ruby, etc.)


And 'auto' isn't the same as no type declaration. Auto still enforces type consistency, so its not that foreign to existing C++ expectations.


Having the type be inferred is precisely what omitting a type declaration does in a static language. From the point of view of a pedantic type systems theorist, Python is like having a static language where every variable has the the same type, "Object".

Anyway, they are talking about documentation. Many people think that having to peek inside a function to know what it returns is worse than having a compiler-checked type declaration. In fact, in most languages with type inference there is still a strong convention to write full signatures for all top level functions, as a form of documentation (return type inference is left for lambdas)


I suspect that over time the C++ community will settle on a set of conventions around the use of auto in this context. Much like how passing in a mutable reference is considered a no-no and you're expected to instead pass in a mutable pointer so it's obvious to the caller that you can change the value via the parameter list.


That's not a C++ community convention, it's just another bone headed part of the Google C++ coding standards. It's stupid because now everything is potentially nullable and every single function will start with:

    if (!arg1 || !arg2 || !arg3 ...) {
        what_I_should_do_here_isnt_really_clear();


I'm not a fan of the "pointer means mutable" idiom either. I feel you should only use a raw pointer type instead of a reference if you want nullptr to be a meaningful value. Value semantics are great.


I'm not a fan of idealism for the sake of idealism. It's practical to be able to tell at the callsite that the parameter can be changed by the function/method.


It's been a C++ convention to use pointers for parameters that are meant to be changed for a long time.

func_call(&var1);

is most definitely a C++ convention bud, and it has nothing to do with google.


Exactly. auto ensures consistency, but it eliminates the need to officially declare intent - which was a key part of type safety.

Not only did you need to use the type correctly, but you needed to declare the desire to use a specific type from the get-go.


I think in any sane library, public API functions will have declared return types. It's only for small helper functions inside a source file that will be autoed. I agree that misuse of auto is going to be terrible, though.


Same can be said about using 'auto' for variable type declarations. It all comes down to "use, but don't abuse" (as most things in C++) - it can improve readability, if used moderately; and it is up to the programmer to judge where to use it.


The compiler knows the inferred types anyway. And several other languages have tools to query these types.

Maybe such a tool for C++ will also appear?


C++ IDEs already offer such feature.


Oh cool. Can you mouseover to see the type?


Yes, at least with QtCreator and KDevelop.


Kdevelop 4.7 just came out and it is glorious. Just can't wait for the qmljs plugin to be mainlined.


Note that this can be used for static functions, I don't think anyone would find it in an API documentation. The real reason I see for this is reducing voodoo in template libraries, eg forwarding a call T::something() for a generic type 'T'.


What happens if a header file declares a function to return auto, does the compiler have to wait until link time to find out what the type is?


No, types are completely determined before link time.

An auto return type means the type is inferred from the type of the expression that the function returns, so it's known from that.


Interesting, could you elaborate on this a bit more?

Say I have a header file "foo.h" with an "auto foo();" declaration. Another file (eg, "bar.h") imports foo.h. How can the compiler do type checking when compiling bar.cc without also parsing foo.cc to determine the return type of foo()?


Inferrence isn't magic and has sensible limits.

To quote:

> Of course, this requires the function body to be visible.

https://isocpp.org/wiki/faq/cpp14-language#generalized-retur...


If there's no function body in header (non-inline function), then it won't compile.


Type inference has been a fantastic blessing for me in C#, so I'll never complain about having to type locals... by extension, implicitly-typed privates seems to make sense. But the public interface of a class? That just feels one step too far.


What if it's a private interface, like a local function? Or a public interface with limited consumers? The language should allow you to write your code the way you want.

Requiring pointless verbosity on some hope that somehow that'll help bad programmers write better code seems like an odd conclusion.


Yeah, we'll end up with some type of Hungarian notation for function naming. A lot of 'Modern C++' seems to be taking over what is really the job of an IDE, just because the original C++ syntax was so verbose.


Now, for the fun part, imagine you have to integrate a third-party cpp library, with an API like "auto fooBar()".


A third party can do that but if it doesn't also provide the source for fooBar, you won't be able to call it, making it fairly useless.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n363...:

    Of course, using such a function in an expression when
    only a forward declaration has been seen is ill-formed:

    auto f();    // return type is unknown
    int i = f(); // error, return type of f is unknown
And https://isocpp.org/wiki/faq/cpp14-language#generalized-retur...:

    Of course, this requires the function body to be visible.


Sure, auto probably shouldn't be used on a function that's part of the exposed API of a library, rather than something internal to the unit of code it is part of.

Its kind of weird to see people complaining about a C++ feature because its not appropriate to use indiscriminately and requires some discipline -- that's historically been pretty much the whole of C/C++.


My comment was mostly tongue-in-cheek, it will be misused in some time and place, but is not a serious issue.


Agreed - the popularity of implicit typing is surprising to me. It seems to make code much less readable and comprehensible. In a good IDE I suppose it doesn't really matter because type information could be provided automatically, but code isn't always read in a good IDE.


Which is much less readable:

map<unsigned int, map<int, vector<string>::iterator> >::iterator getSomeIterator();

or:

auto getSomeIterator();

Function name and context usually is sufficient to know what SomeIterator refers to, there is no need for horrible STL constructs to try to explain it.


The first is readable and I know what it is. Not as readable, but at least I know what it is!

I believe you don't need the space between the > > any more, since C++11?


Readability is about how quickly you can figure out what's going on. There are only a few bits of syntax you need to know what's going on in the first example, but it requires mentally matching together the angle brackets correctly, and it emphasises the type over the function name.

In most cases you can scan over the type ('map blah blah...iterator') but that's not reading and in any case will quickly fail you with nested template types, if you're unfortunate enough to have those.


Functions that return iterators are never called getSomeIterator(). Instead they're called stuff like erase(), insert(), or even nonsense words like crend().

And whether a function returns an iterator is not consistent even within the STL:

    auto loc = container.find("name");
What type is loc? If container is a std::map, then loc is an iterator. If container is a std::string, then loc is a size_t.

If you had used the explicit iterator type, you would at least get an error message immediately with the above line, instead of hoping your code does something that size_t doesn't support.


Or, more likely

std::map<unsigned int, std::map<int, std::vector<std::string>::iterator> >::iterator getSomeIterator();


I like auto. But I would probably write:

    MY_TYPE::iterator getSomeInterator();


In fact, with an IDE, this argument is moot. You can have the type anyway.

Then, we do use template parameters already, for which we usually don't know the type. I can't see why we'd bitch about 'auto' and not about the template parameters.

It's just the same thing: coding against interfaces and not implementations.


A key difference is that we are being told to use auto (but not templates) gratuitously, even when there's only one possible type.

I prefer to make functions ordinary, and only templatize functions that need to operate on more than one type. There's good reasons for this: the compiler is less effective at type-checking templates, they require the function body to be visible, and they may fail to warn you when passed the wrong type.

"auto" suffers from all those problems, and yet we are being told to use it whenever possible. That's bad advice.


Template is explicit; auto can sneak under your radar and look like things you already think you know how they work. Any change to the mainstream syntax can be troublesome at first.


I don't see how auto is less explicit than a template when it comes to involving implicit interfaces.


Remember this is primarily for non-public facing or complex objects. If you are looking at someones API on github it should not be using auto for return types.


Just gather the result in an auto (auto&, const auto&,...) variable et voilà


Edit: see child comments to see why this is a bad idea, at least with native types. Maybe typeid() is better

You have a point there

what you could do is:

return (int)x;

return (YourClass)value;

(then the header and implementation are auto but you still know what the code is talking about

(Or just put the type there as usual)


Except you may have a conversion and you don't know it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: