jamoma / JamomaCore

Jamoma Frameworks for Audio and Control Structure
Other
36 stars 14 forks source link

Stance of Jamoma on use of auto #350

Closed jcelerier closed 8 years ago

jcelerier commented 9 years ago

Hello,

I raise this point to question about the use of auto in Jamoma's coding guidelines, and to see if it should be recommended or not, since it can at the same time make the code more concise for the same meaning, but requires a bit of thinking when reading the code (even if it quickly becomes an habit :) )

A quick presentation : The main use of course is to prevent writing twice the same type, like in :

TTSomeType* var = new TTSomeType(...);

by replacing it by :

auto var = new TTSomeType(...);

It can also be more terse when trying to work with iterators : instead of :

TTVector<TTSomeType>::const_iterator it = vec.cbegin();

One can write :

auto it = vec.vbegin();

However, one must be careful with it, since it only propagates the type, but not the reference qualifiers. For instance, in range-based for loops :

TTVector<TTSomeType> vec;
... 
for(auto myVar : vec)
{
      myVar.modifyingOperation();
}

Here, the variables will be copied each time. and vec won't change.

The correct way in this case is to write :

for(const auto& myVar : vec) // or without const if it is a modifying operation

And, (but I didn't see this in Jamoma so far), in the case of "proxies" on vectors that would for instance behave like list comprehensions in python (multiple libraries implement this), and return temporary values, it would be necessary to make a capture :

for(auto&& myVar : a_proxy_wrapper(vec))

A good explanation on auto&&'s use for generic code is this SO post : http://stackoverflow.com/a/13242177 (but I would highly recommend to anyone interested in very good practices to read the Scott Meyer's book "Effective Modern C++" which explains it in-depth).

Finally, in C++14 it is also possible to write functions with a deduced type :

decltype(auto) makeABigIntVector()
{ 
    return TTVector<int>(1000);
}

This is mostly interesting when writing templated code :

template <typename T>
decltype(auto) fun(T&& val)
{
    return val.aMethod();
}

However, I'd reserve this only to "core library stuff" (like TTValue, TTObject, TTElement) which could greatly benefit of genericity in their implementation, but not to "mundane" classes and methods that operate on very specific domain objects, since this would make them harder to read in a glance.

tap commented 9 years ago

I'm generally all for auto provided that its use is beneficial, which it often is.

In the case of for-loops and iterators it also helps avoid mistakes and is IMO clearer. In cases where it is convoluted to use it then don't. I appreciate the clutter reduction, so if takes more clutter (e.g. having to cast an initializer list to a type) then it doesn't seem worth it.

I have not made an issue for reviewing our template code yet. A lot of our templates should just go away because they duplicate stuff in the standard library (reflecting our origins of long ago from being written in C).

My favorite feature C++14 is human-readable errors from templates, but decltype(auto) is also very cool :-).

tap commented 8 years ago

I guess we all agree :-)