I wonder how wide spread dislike of "auto" is in c++ (I've seen that a few places) when the equivalent type inference has become fairly standard and preferred in other languages like C#, Rust, Go, etc...
I'd avoid the second example since you'd need to know the return type of selectCarById to know what the actual type that will be returned is (the name doesn't help, it might return something like, say, a "ref<Car>" or something like that - e.g. in a game engine i worked on a couple of years ago all resource pointers were passed around encapsulated in a special template that handled automatic resource management - methods would still be called something like "GetMesh" but what you'd get wouldn't be a "Mesh" but a "TResRef<Mesh>", however since in other places in the engine you'd work with "raw" Mesh types, unless you knew what GetMesh returned - which could be the case for, e.g., some programmer that normally worked with at a completely different subsystem with its own rules - you'd might expect a "auto mesh = foo->GetMesh()" to be a "Mesh" but instead it is "TResRef<Mesh>").
I sometimes see people stating exactly this, but then writing:
`doSomethingToACar(selectCarById(carId));`
Kind of weakens the argument. I'm not sure what's the best approach, but I'm usually ok with autos even when the type is not explicitly known - when reading code, I do not really need to know what exact type a variable has ("it's a car, goddamnit, it says so in the name!"), just how it's used (and then meaningful function names become very important).
Traditionally C++ code is often considered harder to read than code in these other languages, and the "excessive" use of 'auto' does not make understanding code easier. Still, according to my observations the split in opinions on this is about 50/50; mine is that the use of 'auto' improves the "genericity" of code (on par with the use of templates) and its amenability to refactoring with less chance to make a mistake. As to the readability of code, it also improves due to not having to repeat yourself as often - as long as the names of the variables remain self-describing or are clear from the context.
I'd also say that using auto makes your code easier to read, especially when you are the user of generic code. Looping through a vector where you need to keep track of the iterator, for example.
for(auto iter = vec.begin(); iter!=vec.end(); iter++)
for(std::vector<project_namespace::class_name>::iterator iter = vec.begin(); iter!=vec.end(); iter++)
Yeah, this is exactly what i dislike - unless the declaration of "vec" is somewhere close by (and assuming it isn't itself "auto" :-P) you have no idea what "i" is.
Especially when that "auto i : vec" should have instead been "auto& i : vec" or "const auto& i : vec" and now you are at best wasting cycles and at worst writing to copies that will soon be discarded, ending up with a bug that can be very hard to spot.
I love the idea of auto range-based iteration but it's full of warts like the one you mention. Recently I found myself wanting an iterator over a combinatorial family.
Generation of a single solution: 3 easy lines (calling on a few hundred lines of goofy math that actually describes the structure, but that's common to all of these approaches)
Writing a for-loop to fill a std::vector of solutions -- about 10 lines of a familiar stack-walking pattern which could confuse a novice.
Making a fake container that defines a begin() and end() along with a nested iterator class: about 20 lines of necessary boilerplate, another 20 lines to replicate the stack-walking, now sprinkled about the boilerplate. The novice is completely bewildered, so we add another 10-20 lines of comments to explain it.
So I have this strong urge to keep the first two implementations in place, just to provide a gentler ramp. But I won't use the code in the end, so it would only add maintenance overhead, so a lone tear rolls down my cheek as I delete the clear, readable code.
In python, this is often as easy as changing square brackets to parentheses to change a list comprehension into a generator.
I usually write auto &i : vec out of reflex, but left the reference part out into visually match what the parent had, with no reference. (But an iterator, so not having that issue.)
> Perhaps the people who dislike auto in C++ would also dislike the equivalent feature in other languages but they just happen to not work in them?
How do you reconcile that world view with the fact that people are shipping billions of line of codes that obviously work in languages where until recently you couldn't even write any type anywhere (JS, Python) ?
I'm not sure what is there to reconcile or even what world view you refer to. Personally i do not use these languages much and when i do it is usually very short code and looks very different to code i'd write in a language with static strong typing.
I don't think so. auto adds some more complications in C++ than var or let in other languages. Consider "const auto& a = x" vs "auto a = x". What exactly is the type of a? It depends.
Auto makes it harder to know the type in question, if C++'s auto is slightly more cryptic than var or let in other languages, doesn't really matter that much if what you dislike is not knowing the type in question in the first place.
But honestly i can only talk about me here, i can't guess why some imaginary other developer who dislikes a feature does dislike it.
I think it was welcomed with open arms by less experienced devs because it made code easier to compile, and rightly so. C++'s compiler messages are off-putting.
For others, it was worrisome because it made code easier to compile, and rightly so. If it complies it doesn't mean it's correct.