Hacker News new | past | comments | ask | show | jobs | submit login
C++ 11 Auto: How to use and avoid abuse (acodersjourney.com)
58 points by ingve on Feb 14, 2016 | hide | past | favorite | 46 comments



I'd be more than annoyed if I saw someone name a function "xxInteger()" because it returns an integer.

I don't actually think the first example was that bad, modulo some context. Sometimes even knowing the type for this kind of thing isn't super important to understand what the code is doing; ala opaque types.


Coming from the Apple ecosystem, descriptive names are par for the course. Most code I end up with is written by autocomplete anyways, so writability is less relevant to me. However, when I go back and read the code later, I want to know as much of the intent of the piece as possible.

Apple publishes some very good guidelines for Objective-C and Swift, the latter here: https://swift.org/documentation/api-design-guidelines/

Generally, I'd name this method according to the role of the result, and not it's type. While "xxInteger()" isn't good, "numberOfXX()" returning an integer type does improve readability and would still be understandable assigned into an auto.

Remember, you're not writing code for you, you're writing code for future you. Or worse, for the next guy who comes into the codebase. They should be able to derive your intent without having to figure out what each method signature is, and reading all the API docs due to lack of code readability.


I agree. When the return type changes now you'd have to change every spot it's called regardless if the return value is used or not. This would be very annoying if you don't have a refactor function in your IDE or if the ammount of changes crosses a company policy trigering a full program test taking days of your time, etc.

The original function name was named poorly however.


I agree. More so in that example where the explicit int return type was used. One can certainly argue that the original function name isn't good enough, but I would hate to see "type names" being appended to functions (reminds me of the old hungarian programming notation for variables).


What exactly is annoying?

I always want my variable names to be as long and descriptive as possible. We're no longer in the teletype era and our monitors are huge. With autocomplete there is no reason to keep variable names short


Thats the only acceptable way to write code, but it doesn't mean that names can't be too expressive, for example I wouldn't accept nameing like this:

> RandomizeArrayPositionUsingFisherYatesShuffle

Since the algorithm detail is something I don't want to think about when I use it and something that the implementer should be able to change without changing the contract.


Visual clutter bothers some people more than others. It bothers me a lot.


"auto a = ConjureMagic();" "SetMagic(a);"

The problem here is actually is an old one of failing to separate a getter from a command.

It looks like ConjureMagic is causing side effects and modifying the state of whatever class it belongs to.

This is also the reason one can't answer the question "what the heck is a?". If the "ConjureMagic" is only a getter and does not modify class state, it may probably need a better name, like "GetMaxMagicPossible". That renders an auto no longer confusing, because this name explains more than the return type. If, on the other hand this is just a command to conjure the magic and we are getting the remaining amount only to immediately pass it to the member "SetMagic" function, then there was no point in returning this value - it could be done inside the "ConjureMagic" itself.


Having Getters for each member variable always seems fine and reasonable. It's when you have getters that do "magic" that I feel a little.. unsure. Like if it's taking a member and returning it in a different unit that seems kosher... But there is a fuzzy line where at some point the Getter is doing too much work to genuinely be a getter. It gives a false impression for the internal structure of the program. But conveying the const'ness is important as you describe (or semi-constness if you have caching)


I'm of the somewhat unpopular opinion that "getters for everything!" is a philosophy that sounds good on paper, but results in writing a lot of getter and setter functions and feeling safe, while ignoring these sorts of traps cropping up everywhere.

Member variables are easy to reason about; they behave exactly like the type they are, and in the case of built in types, have extremely consistent behavior. Getters / setters are a black box of mystery; I like to reserve that pattern for when there's going to be extra work to retrieve some value, so my call site knows it needs to tip-toe around possible failures. While I can see the value in using getters/setters for everything in something like an API or framework, I don't see the value in trying to use them all the time, "just in case."


no, having getters for each member variable is a sign of pervasive action in distance and lifetime problems.


No.

In Herb Sutter's words, avoiding auto since it makes the code "unreadable":

...reflects a bias to code against implementations, not interfaces. Overcommitting to explicit types makes code less generic and more interdependent, and therefore more brittle and limited. It runs counter to the excellent reasons to “write code against interfaces, not implementations”

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


The "unreadable" or "annoying" example from the article is only unreadable and annoying because the programmer was new to the project when he read the two offending lines of code.

I believe Stroustrup is correct that we're all beginners at some point, but we quickly move up. It makes more sense to optimize for "proficient, but not expert" than to optimize for "beginner," because more people are at the proficient level, and they stay there longer.

I agree that code shouldn't be unnecessarily complex. But I would quit any project that constantly brought up "but what if a programmer were brand new when they looked at this code?" in reviews. Then again, if other programmers have the same reaction, perhaps the project really would be full of nothing but beginners.


Why this dismissive comment? auto is definately overused in ways that are unreadable, exactly like the blog author says. Marking the type explicitely may be less generic in a way, but it helps readability so much by providing redundancy.


The author only gives two problematic usage examples, the first of which (ConjureMagic) nercury correctly addressed earlier as a symptom of poor OO design (related to the 'code to implementations' quote above).

The second issue (async) is quite similar in my opinion, and in practice your async handler will be explicitly decoupled and strongly typed at some point for reasons of testability so the example is describing also an OO design issue and not an issue with auto.

There may be real problems with auto but this article did not provide any compelling evidence of them.


auto, the new range for and lambdas are my most used C++11 features. Also make_shared/make_unique.

  auto ptr = make_shared<T>() 
Reads very nicely so I agree that if the type should be somewhere in the auto expression. That is, use auto to remove redundancy. I just wish they would have extended type deduction to lambda arguments so I could do:

  [](a,b){ ... }
Instead of:

  [](int a, int b) {...}
My understanding is that they're allowing:

  [](auto a, auto b) {...}
Bleh.


auto with lambdas can be quite dangerous if you are adding different types inside their bodies. Type promotion rules should be well understood. During code reviews we spotted several overflow bugs when using ints because the dev were thinking auto as a sort of very powerful resource.

Explicit casting if often required to make sure subtle bugs won't show up in production.


What do you mean about promotion rules with auto?


Couldn't that have been found by turning on the signed-to-unsigned conversion warning?


> [](a,b){ ... }

Is valid if a and b are types.


Yeah, I guess that's where the committee is hesitant to deduce parameters without the auto qualifier.


How much of these concerns could be alleviated by an IDE that makes the types more visible?


That's what Herb Sutter argues in his Almost Always Auto post, but I would disagree:

1. The IDE cannot deduce the type within templates, and more code is moving to templates (e.g. generic lambdas in C++14)

2. Code is often read outside of IDEs: code review, search engines, etc.

3. Should C++ become a language that requires an IDE to work effectively, like Java? Probably not.


I would be very surprised if someone can meaningfully review C++ templates without an IDE.

Really not reviewing a program inside an IDE is a poor idea in general.


Some of us still use emacs and vim.


Yeah, some of us still listen to vinyl and tube radios.


Unfortunately all the ides I tried make it non trivial to write extensions. I program nearly 9 hours a day and using a tool that prevents automation of common tasks is suboptimal.


On my case, they provide all the necessary automation features I care about.


Out of curiosity which Language and IDE do you use?


Java, Scala, F#, C#, C++, JavaScript, SQL.

VS, Netbeans, Eclipse, Android Studio, SQL Developer.


Surely people using vim/emacs for serious C++ work are going to at least have ctags, and probably something like YouCompleteMe?


I use emacs with rtags.


To clarify, with plugins such as ctags, rtags and YouCompleteMe. I would never be able to write large C++ programs in vanilla vim. Maaaybe plain C, but definitely not C++.


Somewhat related, C++14 gets 'auto' for function return types, which really makes me nervous (C++11 has a form of this, but not as powerful).The D programming language uses 'auto' as the return type for many of the functions in the standard library and this makes it, IMO, somewhat cumbersome to use.

In general, I don't think C++ (or D) devs should be using deduced return types in the public interface, if at all possible.


So auto allows you to deal more easily with c++ crap, especially STL. My first thing to do in all my c++ project is to import my in-house STL wrapper, which makes STL usable for me. I never understood how people can work with raw STL. I don't like at all working with templates and i am using it only in internal class implementations. C++ without templates is so much more beautiful.


Would you mind giving some examples? I don't find STL to be crap at all.


std::unordered_map<std::string, SomeClassName>::iterator it = hashmap.begin();

vs

auto it = hashmap.begin();

I find auto useful for cutting down some of the verbosity of templates STL containers, but I can see how over use can lead to code requiring much more referencing if maintaining code that rarely defines types.


Oh no, I agree with that. I was specifically talking about fenesiistvan's point about his STL wrapper. I was wondering what his use cases were.

No doubt auto is extremely useful in a case like the one you mentioned. In fact, even more so in here:

for (std::unordered_map<std::string, std::unordered_map<std::string, long>*>::const_iterator it = a.begin(); ...)


I am used with the old Delphi / C++ Builder style. I think that it is much more clear than than bot the STL and the new trendy C11 style.

So my hashmap handling looks like this:

MHashMap userlist = new MHashMap<HUser>();

HUser *user = userlist->First();

while(user) { user->DoSomething(); user = userlist->Next(); }


I think one of the key things that makes 'auto' much more painful than 'var' is that in Visual Studio, the intellisense in C# is much more reliable than C++. Any ambiguous statement like the first example is quickly and resolved in C# with a quick F12. In C++, this doesn't always work especially when you're using any kind of cobbled together or hybrid build system.

A lot of times, the type is unimportant but when it is, this kind of usage can bloat a simple task into 5 to 15 minutes of hunting through headers or grepping.

It's strange to think of an IDE feature so impacting a language feature. The stack is not supposed to affect in that direction but this is one case where it really does.


Will best practice for the auto keyword change when c++ concepts finally arrive?

Of the 3 options below, the third seems best to me:

  SomeReallyLongTypeName* x = foo();  // old-school

  auto x = foo();  // c++11

  pointer x = foo();  // c++17 concepts


you can already do: auto *x = foo(); Which is actually more readable than "pointer".


Perhaps a better example be something like:

  smart_ptr<auto> x = foo();


The unlikely return of VB's hungarian notation...


The example at the start would be equally mildly confusing if it was written as SetMagic(ConjureMagic());. The problem is not the auto. It's a normal case of non-ideal function names.


Unsure of the explicit typing one. Don't the Core Guidelines say to use it in that case? The IDE's going to tell you the return type anyway.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: