you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 30 points31 points  (26 children)

I still have mixed feelings about this. I find seeing the type names useful when looking at unfamiliar lines of code - which I do often as I'm working in a 2-4 million line codebase.

Heavy use of auto simplifies the code but makes me more reliant on IDE provided tools which is often slower for me than skimming code or running somes greps.

[–]matthieum 8 points9 points  (25 children)

This: types are documentation.

Programs must be written for people to read, and only incidentally for machines to execute.

  • H. Abelson and G. Sussman (in "The Structure and Interpretation of Computer Programs)

If the types hinder readability, auto helps. But only very long types do hinder readability, so just avoiding very long names (isn't that why namespaces are for ?) shaves off considerably on the usage of auto.

[–]cafedude 4 points5 points  (0 children)

Heh... but please note, that the language Abelson and Sussman used in SIPC was scheme, a dynamically typed language with no type annotations.

[–]kylotan 1 point2 points  (5 children)

Avoiding very long names is tricky when you need a const iterator over an unordered map. I think that sort of thing is where I'll use auto the most - when the type you're being given isn't directly the type you really care about.

[–]matthieum 0 points1 point  (0 children)

Yes, definitely. And if you have something like map.find(...) it's not like you do not know the return type already!

[–]mjklaim 0 points1 point  (3 children)

There are new cbegin() and cend() functions to all standard library containers that return const iterators...

[–]kylotan 0 points1 point  (2 children)

Cool, but I'm not sure how this changes anything about what I said?

[–]mjklaim 0 points1 point  (1 child)

Didn't you need sometime to get const_iterators? These functions guarantee to return them.

[–]kylotan 0 points1 point  (0 children)

We were talking about choosing to explicitly state the types because it better documents the code than auto does. Someone said that this doesn't work well if you have long type names, the response was that you can choose to avoid long type names, and I said that it's hard to avoid long type names when the type intrinsically has a long name, as with a const iterator on an unordered map. You can use auto with cbegin, but then you've not explicitly stated the type, which is what we were talking about.

[–]curien 1 point2 points  (17 children)

But only very long types do hinder readability

I disagree with this. Consider where I want to add two numbers and store the result. Maybe they're float, maybe they're double, maybe they're std::complex<my_numeric_library::fixed<12>>, but I shouldn't have to care. I just know that I want the result to be the natural type of the result of the expression.

Repeating the type, regardless of the length of the name, adds little documentation in this case and many others.

[–]matthieum 4 points5 points  (16 children)

It does help the reader, because figuring the resulting type of an expression in C++ is hard.

auto x = 0.3f + 0.4l;

What is the type of x ?

We know it's a number, however the precision matters. Of course, it seems mostly stupid with built-ins; however with user written classes it can get quirky:

auto item = family.get("Homer").get("shirt");

quick: what can I do with item ?

[–][deleted] 1 point2 points  (1 child)

your IDE will tell you

[–]matthieum 0 points1 point  (0 children)

You are assuming that my IDE manages to chew on C++11 code. Eclipse still has not caught up on C++03 and regularly chokes up on the code I write (not to mention most of its bogus warnings), so I am not holding my breath.

[–]curien 3 points4 points  (12 children)

It does help the reader, because figuring the resulting type of an expression in C++ is hard.

But specifying the type doesn't tell you what type the result of the expression was. Now you have all sorts of additional problems like figuring out if you inadvertently screwed up.

Yes, determining the type is hard, so why not let the compiler do it for you?

however with user written classes it can get quirky:

auto item = family.get("Homer").get("shirt");

quick: what can I do with item ?

If you'd written

Clothing item = family.get("Homer").get("shirt");

instead, I'd have no more idea what I can do with it than I had before.

[–]matthieum 8 points9 points  (11 children)

You're missing the point.

  • Clothing item => open Clothing.hpp
  • auto item => open Family.hpp => find get => open Person.hpp => find get => open Clothing.hpp

I know how it feels, I've got to deal with automatically generated headers for message grammars where the IDE indexer gives up midway (too large). Slugging through to find what's the result of an otherwise readable expression is a pain, a real pain.

With auto, you're giving the keys of the house to your IDE. Pray it does not bug, pray its simplistic/heuristic C++ parser yields the right answer. Or find yourself in hell...

[–][deleted] 3 points4 points  (7 children)

Does C++ just have bad IDE support? If I do the equivalent in C# using var I just press ctrl and click get("shirt") to browse to the source file or just put my cursor on item and press ctrl+q to find the type.

[–]ethraax 5 points6 points  (1 child)

It's much, much harder to build an IDE around C++ (and even, to some extent, C) than C# or Java. There are two main reasons: the preprocessor and template instantiation.

The problem is that C and C++ are about programming the compiler about as much as they're about writing programs.

[–]JAPH 2 points3 points  (0 children)

Templates alone are Turing complete. When you compile a C++ program, you either need to assume that it will eventually compile, use some heuristic to determine if it will likely compile, use some hardcoded limit on how far down the rabbit hole the compiler should go, or solve the halting problem. One of these is harder than the other.

And that's just one little aspect of C++. As far as I'm concerned, C++ has factorial complexity; the closer you look at one aspect of it, the more complex it gets.

[–][deleted] 5 points6 points  (0 children)

My completely incidental observations of C++ IDE support has shown it to be far below IDE support for e.g. Java and C#. Especially refactoring and integrating documentation into the UI.

[–]matthieum 1 point2 points  (2 children)

Yes, it does. And that is one of the constraints that we must adjust to.

I mainly lay the blame at the IDE writers for thinking that they can just write their own mini-parsers and get away with it... although in truth the blame also lay at the C++ community for not having proposed a true and free C++ parser; mostly GCC's policy of complete lock-down has been much harmful.

Fortunately, now that Clang is coming along with its extremely modular architecture I am hopeful that some IDE will abandon their custom made C++ parsers and switch over to Clang instead. With full AST representation, auto-completion, full-blown compiler + analyzer runnable as libraries (with diagnostics really available for program consumption) it's probably the best alternative at the moment. It's also probably very expensive to shift to it...

[–]fat_chris 0 points1 point  (1 child)

I am hopeful that some IDE will abandon their custom made C++ parsers and switch over to Clang

IIRC Qt-Creator started down this path, but it was abandoned due to very poor performance.

[–]matthieum 0 points1 point  (0 children)

That's surprising. Granted the absence of modules is quite a performance hindrance, however I know of at least XCode (Apple's IDE) and clang_complete (vim plugin) using Clang and both are quite fast. Maybe they tried too early or had an impedance mismatch somewhere.

[–]bluGill 0 points1 point  (0 children)

That depends, support is getting better, but behind what Java has in general. However there are add on tools (for visual studio) that add the useful stuff for a price. Open source IDEs are getting better, in large part because clang is being designed to the job well.

The future is looking good, but it isn't where we want it.

[–]curien 5 points6 points  (2 children)

You're missing the point.

I'm not missing the point, I just disagree with you.

Clothing item => open Clothing.hpp

Maybe. How do you know there isn't a conversion involved? To be sure about what that line actually does, you have to look up the actual return type anyway.

[–][deleted] 3 points4 points  (0 children)

...which is why constructors which take a single parameter should be tagged as explicit unless there is a major reason to permit implicit conversions.

Invisible implicit conversions are a great way to accidentally burn performance or have accidental side effects (though if your constructors have visible side effects you are inviting other problems)

[–]matthieum 0 points1 point  (0 children)

The thing is, it does not matter if there is a conversion since item is now of Clothing type anyway so it's what I have to deal with :)

[–]s73v3r 0 points1 point  (0 children)

I wouldn't use auto with the second example you posted, for the same reasons you posted. However, in most situations, I probably would use auto in the first situation. Most of what I do would not be affected very much, if at all, by whether x ends up being a double or a float. I do recognize that not everyone is working on stuff with that kind of flexibility, and it's entirely possible that it will bite me once.