On Wed, Oct 1, 2014 at 6:27 PM, Ehsan Akhgari <ehsan.akhg...@gmail.com>
wrote:

> On 2014-10-01, 7:42 PM, L. David Baron wrote:
>
>> On Wednesday 2014-10-01 16:24 -0700, Eric Rescorla wrote:
>>
>>> Obviously, if you have some argument that auto is bad programming
>>> practice
>>> or a hazard and should thus be forbidden, that's something you could make
>>> and
>>> see if people generally agree...
>>>
>>
>> I think there are cases where |auto| makes code substantially less
>> readable, and cases where it's fine.  I don't think I have enough
>> experience reading code using |auto| to say exactly what's in which
>> set, but I have mandated less use of |auto| in code reviews.
>>
>> Some of it is simple readability; there are cases where seeing the
>> type of a variable allows its name to be simpler while preserving
>> the same level of readability, and if we're going to hide the type,
>> I'd want it to have a more complex name to make the code obvious.
>>
>> But I'm also worried about use of auto leading people to stop using
>> const or & where they should be (particularly where |auto| instead
>> of |const auto&| leads to unnecessary expensive copies).  (And I
>> think knowing whether I want |auto| or |const auto&| requires
>> knowing the type, which makes the feature less valuable to me.)
>>
>> I'm fine with just enforcing reasonable judgment in code reviews,
>> although I suspect some people would be bothered by having code
>> reviewers enforce style rules that aren't written down.
>>
>
> FWIW, I have had some actual practical experience in using |auto| in the
> LLVM code base (and with reading code that uses it).  Here is my take on
> things:
>
> * Beware of using auto in cases where types can be constructed implicitly
> from other types.
>
> This is the most important rule, I think.  Here's an example of how this
> can introduce real bugs.  Let's imagine you have code like this:
>
> nsIFoo* FooGetter();
> nsCOMPtr<nsIFoo> foo = FooGetter();
>
> DO NOT replace the type here with auto:
>
> auto foo = FooGetter(); // NOT COOL!
>
> After this change, foo will be a raw nsIFoo*, which is a weak reference,
> so this changes the meaning of the program.
>
> Arguably, this is not an issue with auto, but with implicit conversions.
> It is one of the reasons why implicit conversions are evil.  :-)
>
> * |auto| itself is rarely what you want (unless you know the underlying
> type is not copyable), you probably want |auto&| for references if you
> intend to modify the original value, or |const auto&| if you don't.  A
> sufficiently smart compiler should be able to figure out that it doesn't
> actually need to create a reference under the hood if the type it's seeing
> is a built-in one.  (clang seems to be able to do this based on a quick
> test.)
>
> * If you find yourself typing the type once in the statement already, use
> |auto|.  Example:
>
> auto ptr = static_cast<Class*>(foo);
>
> * Do not use auto for functions that can return different types that have
> the same interface, as it obscures away the operation performed on the
> type.  Example:
>
> class Container {
>   // ...
>   // Assume that the below iterator types map closely to the STL concepts
>   iterator foo(int x);
>   reverse_iterator foo(string y);
> };
>
> Container c;
> auto it = c.foo("str"); // What kind of iterator do I have?!
>
> * Do use auto for situations where the type doesn't really matter.  For
> example, if you have code like below:
>
> foo(bar());
>
> And want to put the call to |bar| into its own statements, and do not care
> what the return type is, use auto:
>
> const auto& result = bar();
> foo(result);
>
> (Of course, depending on the nature of |foo| and |bar|, not all code that
> looks like this should be refactored this way.)
>
> * Do not use auto outside of a local scope.  This helps restrict the
> implications of auto to a hopefully smaller amount of code.
>
> * Do not overuse auto.  Consider auto as a handy tool that prevents you
> from typing needlessly.  But if you have code which uses auto all over the
> place, you're *probably* doing it wrong.
>
> * Remember that at the end of the day, code is read way more often than it
> is written.  If in doubt, opt for keeping the code more readable by typing
> in what you mean, IOW, don't use auto when in doubt.
>

I want to add one case, which is when receiving some plain integers from
some kinds of functions, and doing computation based on them. For example:

> nsTArray<nsString> array;
> auto length = array.Length();

In this case, the perfectly exact type of |length| should be
"nsTArray<nsString>::size_type". Before we have |auto|, the common way is
to write int32_t, uint32_t, size_t, or something similar. There are two
main problems of using those types:

1. the variable type may be different with the return type of the function,
which causes (possibly unwanted) implicit type conversion, like converting
between signed and unsigned, or 32bit and 64bit;
2. the return type may change over time, (e.g. uint32_t -> size_t), which
again causes the first problem for previously perfect code.

Hence, I suggest for cases like this, |auto| should be a recommendation.
IIRC, it is one of the cases that |auto| was introduced for.

For cases like:

> for (int32_t i = 0; i < array.Length(); i++)

I even want to write it as

> for (decltype(array.Length()) i = 0; i < array.Length(); i++)

but I feel it too redundant. I hope C++ could support

> for (auto iend = array.Length(), i = 0; i < iend; i++)

but, unfortunately, it does not.

Do you think this case reasonable?
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to