I have written about the code style of having “trailing return types everywhere” in the past. My advice back then was to use them only when necessary. I might have been wrong.
Recently, Jon Kalb wrote about “a foolish consistency”, about the “East Const” vs. “West Const” debate. He points out that leaving code style as it is because existing code has been written like that will prevent any progress in that area. Of course, he is right.
At ACCUConf 2018, Phil Nash presented a lightning talk about “East End Functions”. In that talk, he pointed out, that I had fallen into that same trap of arguing in the lines of “we’ve always done it like that”. Silly me.
Pick your code style
Whether it’s east const vs. west const, brace style, tabs vs. spaces, something that seems exotic these days, like trailing return types, or any other code style hill people are willing to die on: It’s OK. Pick your style, but make sure you pick it for the right reasons.
That does not mean we shouldn’t familiarize ourselves with competing styles. We will at some point have to read or even write code that uses another code style. And no, clang-format will not always save your day and convert the code to the style you like when you check it out and back again when you check it in:
- You will not always read the code on your preferred editor after checking it out. Think about code reviews using diffs online.
- You won’t always write code that way, either. Think about pair programming or just quickly helping a colleague. It’s much easier to use the style everyone agreed on that is not your favorite, than having to use their weird personal style that differs vastly from your
weirdperfectly sensible personal style.
- Especially when it comes to east/west const, trailing return types, and similar code style choices, there might be no tooling yet to do the conversion for you.
Isn’t that an argument against those styles?
Not having tooling available to change to a certain code style means we can not simply automatically convert our whole code base to that style. But that does not mean we have to use the existing style. After all, in a code base that reeks of “C with classes” style, we still are going to use better C++ constructs, right? Right?? I hoped so.
So, having a code base with an old style does not mean we can not switch to another style when we have good reasons. Of course, it can be confusing for the reader to have multiple styles in the same code base or even the same source file. We should have code style consistency at a certain granularity. Depending on which granularity we choose we have several options:
Code style consistency on a per-file basis: Use the new code style for new source files. Either use the old style in existing files or reformat files according to the new style when they have to be touched anyways.
Code style consistency with a coarser granularity, e.g. per library means that we can introduce the new code style only when we create new libraries, or by porting existing libraries to the new style as a whole. Depending on the size of the libraries that can take a considerable amount of time that needs to be allocated explicitly.
When it comes to code style, do not base your decisions on consistency with existing code. The language and our understanding of it evolves, and it is no shame if larger code bases reflect that evolution. Being too rigid just for the sake of consistency hurts our progress in writing understandable code.
That does not mean that you have to switch to “East Const” and “East End Functions” – it’s a decision every team has to make on their own. For my part, I have used East Const for years, mostly on my private projects. I don’t think I’ll get used to using East End Functions just yet though.
I am well aware that this post somewhat contradicts my original post about “trailing return types everywhere”. But that’s life as a developer: We learn, we adapt, we change our minds.
In the southern hemisphere, our code is upside down, which makes the whole “East Const” and “West Const” thing even more confusing!
The only correct programming style is the style desired by your employer.
“leaving code style as it is because existing code has been written like that will prevent any progress in that area. Of course, he is right.”
He may have been right, but the argument is irrelevant. Change for the sake of change is not progress. It’s just a waste of time. That includes change for the sake of making its syntax more like some more fashionable language (Remember when “pythonic” was the thing to strive for? Wait, when was this change approved? 🙂 ).
Absent valid reasons for a change, then the change should not happen. The change needs to be evaluated on its merits alone. I have never seen any arguments for universally using trailing return types beyond mere perceptions, so I haven’t adopted it. If an employer tells me I need to, then I will.
The reason c++ is still described as c with classes is because too many college courses don’t even touch on c++11, leaving the perception of an archaic, dangerous and confusing language. I hope the goal of adopting trailing return types was to allow flexibility (e.g. if it’s usable for lambdas, it should be usable elsewhere), not to generate just another confusing triviality worthy of keeping the unwashed away from the cool kids table.
There are still a couple of reasons holding me back to go trailing return types all the way:
* Visual Studio seems to hide “noexcept” and trailing return types upon closing a function’s body. The latter is very inconvenient if one likes to close scopes by default.
* While most people argue that trailing return types are consistent with lambdas, one can also argue that they are inconsistent with std::function.
* I would prefer some new keyword like “fn” or “func” (not “def” as it is part of the declaration, not the definition) instead of “auto” as that could imply “void” (“-> void” is just very odd) if no explicit trailing return type is provided. Furthermore, introducing a new function keyword opens the opportunity to have “[[nodiscard]]” as the default for such free functions/member methods.
* cppreference.com should promote trailing return types by making it an optional or just the only way of viewing the documentation.