← Back to context

Comment by badsectoracula

1 day ago

> for (auto const & ess : esses) {

The problem with this is that whoever is reading the code as-is does not know what type "ess" is. Sometimes you get the definition somewhere nearby, in which case it is probably fine - assuming it is close enough that it'll be included in a diff - but more often than not you don't know.

Yes, an IDE can probably tell you (probably, depends on the IDE and assuming everyone uses one) but even that requires some extra action like moving the mouse over the definition and hoping it'll give you something. However this wont show up in diffs, PRs, code reviews, etc.

IMO `auto` is one of those C++ features that really needs discipline to use - and when in doubt, i'd rather ban its use (except where you cannot do otherwise) than rely on everyone doing the right thing.

C++ is an IDE type language in my opinion. C is not, because C doesn’t have an expressive enough type system anyway to justify it.

Yes, just use and IDE. This is a problem in Rust as well. And C#, Java, and others.

IMO you should use auto as much as possible. If the code can be written with auto, it should be. There’s no reason to repeat type definitions.

If you can use auto, what that means is the type is already statically known. C++ is a statically typed language; the compiler and tools know what type things are. So, just ask the tools, because they’re not wrong.

It doesn't matter what the type is, that's the whole point!

Moreover, what's even more beautiful? You can change the type of things in the container "esses", and the code doesn't need to change.

If you have the experience, this construct tells you everything you need to know: it's an iteration over a container, visiting every element in order, without copying it, and without modifying it.

You don't need to know any more.

How important is that, the ability to be certain of the type of some iterated value from a container from one line in total isolation? The odds are very good that it's clear from the context, which is why the compiler can infer it easily enough too. And then the consequence of not inferring correctly would be...the code doesn't compile?

Of course some discipline is required - as with just about everything in programming, especially in C++ - but developers in just about every other statically-typed language lean on type inference (including far more extensive type inference) and don't wring their hands about it. It's hard not to see this as a case of Blub - if you learned about typing with `Foo foo = new Foo()`, anything different might seem scary.

...anyway, in this case the real win probably is the range-based for loop, rather than the auto. `for (const Foo& foo : foos)` isn't so bad, but `for (std::vector<Foo>::const_iterator it = foos.begin(); it != foos.end(); ++it)` is pretty rough.

  • > How important is that, the ability to be certain of the type of some iterated value from a container from one line in total isolation?

    As important as the code to be readable.

    > The odds are very good that it's clear from the context

    As i wrote, if the actual type can be seen somewhere nearby (close enough to be included in diffs) then that's fine - it is already in the context. Though that is not usually the case and i personally had to work with code with which i was not familiar and which used `auto` all over the place and had to go hunting for the actual container declaration to see what it is (Visual Studio was not helpful in its tooltips).

    So my actual experience is that i'd rather see the actual type.

    However...

    > anyway, in this case the real win probably is the range-based for loop

    ...yes, the range-based for loop is often the better choice when it comes to readability. And when compared with the iterators, it is pretty much always more readable than them :-P. `for (const Foo& foo : foos)` is basically what i'd prefer to see. It is the use of `auto` i pointed out.