I’m open to auto, but skeptical.
(1) Research-ability. I read a lot of code that is new to me, that I have never
written. I find type statements to be useful as documentation for where to look
for more information about how data structures and algorithms relate to each
other. Traversing a tree or list of data structures by type name while reading
code is a common task for me. But I can’t select and search for auto, auto*, or
auto&.
(2) Mechanics. It’s totally true that if you loop over one collection and put
the values into another collection, subject to some filter, the types involved
aren’t really interesting to reviewing the filter. But if you want to review
low-level mechanics like object lifetime and thread safety, suddenly the types
are really important. I think the “I changed RefPtr to auto and then crashed”
examples in this thread are about mechanics.
I find it strange that, as JavaScript authors adopt tools like TypeScript
because they find type-less programming to be unmaintainable, C++ authors move
toward type-less programming. Perhaps the grass is always greener on the other
side. Or perhaps we can strike a balance and put types where they help us.
Two arguments made in favor of auto don’t fully convince me:
(1) You were always able to hide the types of certain expressions.
I’m hoping the point of this argument is not to say “in for a penny, in for a
pound”, but rather to raise our awareness that we’ve been OK with certain
type-less expressions all along. I agree: I'm OK with hiding types in some
places, especially if surrounding code already provides some kind of type
foothold.
At the same time, I sometimes break expressions into statements to improve
clarity and research-ability or to achieve certain mechanics.
Maybe this answers Darin’s question:
> Here’s one thing to consider: Why is it important to see the type of
> foundSource->value, but not important to see the type of shifts.take(source)?
> In both cases they need to be Vector<ShufflePair>.
In the cited code, ‘shifts’ is declared as HashMap<Arg, Vector<ShufflePair>>,
and HashMap ’take' is well understood to return its value type, so no further
comment about type is necessary for me on this line.
Following this logic, I might be OK with eliding the type of
foundSource->value. But we’re starting to reach a limit. Each time we do this
we create an auto link in the type chain. If I have to trace back three autos
deep in order to understand a type, I’m gonna have a bad time. Each type
declaration is a stopping point for research. Therefore, I don’t prefer the
fully auto version of this code.
Following this logic, I would be OK with const auto& a little later in this
algorithm:
> bool isRotate = false;
> for (const ShufflePair& pair : currentPairs) {
> if (pair.dst() == originalSrc) {
> isRotate = true;
> break;
> }
> }
Might as well use const auto& for ‘pair’: The type of currentPairs is
well-documented locally. If currentPairs were a data member, and not declared
in the same screenful of code, I would want to write out a type for ‘pair’.
Otherwise, I would have to open another file to understand this line.
But somebody said we don’t like const auto&? Is this a gotcha somehow?
(2) You can’t be sure of the stated type, since a type conversion may have
happened.
Knowing that a value is equivalent to a certain type still provides a foothold
for research and understanding mechanics.
We only allow automatic type conversion when we consider types to be reasonably
equivalent. We consider it bad style to convert willy-nilly, and we use the
explicit keyword to avoid errant conversions. For example, we don’t allow
RefPtr to automatically convert to raw pointer.
Geoff
_______________________________________________
webkit-dev mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-dev