Skip to content

Document current coding style guidelines. #2298

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

Axel-Naumann
Copy link
Member

No description provided.

@Axel-Naumann Axel-Naumann self-assigned this Jul 6, 2018
@Axel-Naumann Axel-Naumann requested a review from amadio July 6, 2018 16:10
/// Functions that access only public members of ROOT classes shall be in here.
/// \param a - first TExampleClass to add.
/// \param b - second TExampleClass to add.
double Add(const TExampleClass& a, const TExampleClass& b);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to change the binding of the & (and *):
double Add(const TExampleClass &a, const TExampleClass &b);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes please! :P

Copy link
Contributor

@eguiraud eguiraud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, we really needed this! Is this retroactive for new classes? I.e., should I make RDataFrame & friends compliant?

@@ -0,0 +1,67 @@
/// \file RCodingStyle.cxx
/// \author Axel Naumann <axel@cern.ch>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does this look for multiple authors?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be addressed.

@@ -0,0 +1,67 @@
/// \file RCodingStyle.cxx
/// \author Axel Naumann <axel@cern.ch>
/// \date 2018-07-06
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what date is this? creation or last modification?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be addressed.


// This file demonstrates the coding styles to be used for new ROOT files.
// For much of the rationale see Scott Meyer's "Efficient Modern C++" and the
// [C++ core guildlines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"guildlines"

* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/

// This file demonstrates the coding styles to be used for new ROOT files.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"style" singular?

// Now the same order as for the header:
// ROOT headers in alphabetical order; all new ROOT headers are under `ROOT/`
#include "ROOT/TSeq.hxx"
// Old ones are found in include/ without prefix. Try to use the new ones.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean with "Try to use the new ones"? The percentage of functionality that is available both in ROOT/R* headers and in T* headers is very little afaik?

Or is this a "Try out the new ones when available!" (as in, advertisement more than guideline)? In which case my comment would be that there is no way for users to know whether ROOT offers a ROOT/RString.hxx as a modern substitute for TString.h, except for searching for it in the doxygen docs case by case. And even then the names are not always the same, e.g. the modern TH1F.h is not ROOT/RH1F.hxx.

/// Disabled if `T` is of reference type.

template <int IDX, // Template parameters are all-capital letters
class T, // We use "class", not "typename"; `T` is fine for generic class names
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

damn, that's a lot of search-and-replace in RDataFrame's headers 😋

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries. Some inconsistencies are fine; people won't even notice. It's more important that we agree on what to do from here on.

/// on the template parameters, e.g. `IDX` must be positive, `T` must be copyable.
/// Disabled if `T` is of reference type.

template <int IDX, // Template parameters are all-capital letters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the only new convention that I don't like, it makes template-heavy code a bit heavy to look at (just go to TypeTraits.hxx and capitalize all template parameters...) and macro-like.

Copy link
Member Author

@Axel-Naumann Axel-Naumann Jul 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It helps to identify template parameters as such. I often use a using declaration to "convert" the template param to a type (with type-spelling).

But I see your point. Let's discuss at a team meeting!


// Use `= delete` instead of private, unimplemented.
// To avoid copy and move construction and assignment, `delete` the copy
// constructor and copy-assignment operator:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this mean that you prefer to not have the move-ctor deleted?

/// they "inherit" the virtuality of the virtual base class destructor).
virtual ~RCodingStyle() {}

/// Overridden virtual functions do not specify `virtual` but `override` or `final`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say either override or final: exactly one of the two, as per CppCoreGuidelines

/// Functions that access only public members of ROOT classes shall be in here.
/// \param a - first TExampleClass to add.
/// \param b - second TExampleClass to add.
double Add(const TExampleClass& a, const TExampleClass& b);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RExampleClass

@Axel-Naumann Axel-Naumann force-pushed the CodingStyle branch 3 times, most recently from 0b18907 to f78f9bd Compare July 9, 2018 09:25
@Axel-Naumann
Copy link
Member Author

I don't think we should invest effort in retrofitting this to RDataFrame, but you're welcome to revisit parts as you see fit. Let's first agree on the style. I will present this in a team meeting to discuss it; e.g. the template arguments will be part of this discussion.

@root-project root-project deleted a comment from phsft-bot Jul 9, 2018
@root-project root-project deleted a comment from phsft-bot Jul 9, 2018
@root-project root-project deleted a comment from phsft-bot Jul 9, 2018
@root-project root-project deleted a comment from phsft-bot Jul 9, 2018
@root-project root-project deleted a comment from phsft-bot Jul 9, 2018
static const std::string &StaticFunc() {
// NOTE that this initialization is thread-safe!
static std::string sString = "SomeString";
return sString;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about return "SomeString";?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a) that's not the point of this demo-function, and b) that won't give you a string&.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have improved the code, I hope it's less confusing now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but maybe git commit --amend is better than adding a separate change for this.

* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this header on every file? The top 3 lines are obsolete almost immediately, and git is there for that, while the copyright can be in a file at top level stating that that's the copyright unless a different one exists in the file. Also, many files don't have the header in any case:

epsft-53 root $ git ls-files | grep '\.[ch][x][x]' | wc -l
2847
epsft-53 root $ git ls-files | grep '\.[ch][x][x]' | xargs -n1 grep 'Rene Brun' | wc -l
1739

and many others are out of date:

epsft-53 root $ grep -hor '1995-[0-9]\+' | sort | uniq -c
      4 1995-01
      1 1995-10
      4 1995-1996
    114 1995-1997
      3 1995-1998
      3 1995-1999
   1308 1995-2000
     70 1995-2001
    149 1995-2002
     49 1995-2003
    279 1995-2004
    213 1995-2005
    137 1995-2006
    321 1995-2007
    184 1995-2008
     48 1995-2009
     20 1995-2010
     55 1995-2011
     57 1995-2012
     77 1995-2013
     11 1995-2014
     44 1995-2015
     53 1995-2016
     89 1995-2017
     29 1995-2018
      1 1995-8

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The top 3 lines are obsolete almost immediately, and git is there for that,

There is a difference between touching a file and writing it. I have argued before that this is a nice way of leaving traces also for people with limited participation in ROOT, and it's a good way of knowing whom to contact / ownership.

the copyright can be in a file at top level stating that that's the copyright unless a different one exists in the file

Multiple opinions exist on that one.

Also, many files don't have the header in any case

Indeed we have many files that have a different (c).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a difference between touching a file and writing it. I have argued before that this is a nice way of leaving traces also for people with limited participation in ROOT, and it's a good way of knowing whom to contact / ownership.

I still think that git blame is more than sufficient for that, but the final choice is up to you.

// The first non-comment, non-empty line must be the #include guard.
// Acceptable forms are:
// ROOT_RCodingStyle, ROOT_RCodingStyle_hxx, ROOT_RCodingStyle_Hxx,
// ROOT_RCODINGSTYLE, ROOT_RCODINGSTYLE_HXX
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not choose one only?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What or whom could a difference here confuse? What's the advantage of choosing one? They should be file-local, I sort of like that nobody can rely on them outside this file ;-)

Copy link
Member

@vgvassilev vgvassilev Jul 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should likely mangle at least the component path in include protector. It may become very ugly to debug if the include protector names are duplicate between two unrelated files.

I'd make sense to me to stick with one include protector style (the latter).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choosing only one is good for consistency. Isn't this trying to improve exactly that? I don't really care which one we choose, as long as it's consistent throughout the code. At the very least one choice should be recommended over the others. There's also #pragma once, but since it's not in any standard, maybe we should stay away from that.


// Especially within header files, reduce the number of included headers as
// much as possible, at the expense of more forward declarations.
// EXCEPTION: standard library classes must be #included, not forward declared.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even the easy-to-forward-declare ones?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh, I get your point :)

// Include non-ROOT, non-stdlib headers last.
// Rationale: non-ROOT, non-stdlib headers often #define like mad. Reduce interference
// with ROOT or stdlib headers.
#include <png.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds weird. In principle png.h may depend on stl. That's not a problem for non-ROOT packages but what about the ones that are on the borderline: eg libafterimage and others that are patched by us.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

png.h may depend on stl

No. System headers never depend on C++ and should thus come last.

static std::string fgNameBadPleaseUseStaticFunctionStaticVariable;

protected:
/// FOURTH section: non-public functions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be no THIRD.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// THIRD section: data members.?

double Add(const TExampleClass &a, const TExampleClass &b);

} // namespace ROOT
#endif // #ifndef ROOT_RCodingStyle
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd omit the #ifndef, it's meaning is implied by the previous token ;)

@phsft-bot
Copy link

Starting build on slc6/gcc48, slc6-i686/gcc49, centos7/clang39, centos7/gcc62, centos7/gcc7, fedora28/native, ubuntu16/native, mac1013/native, windows10/vc15 with flags -Dimt=ON -Dccache=ON
How to customize builds

1 similar comment
@phsft-bot
Copy link

Starting build on slc6/gcc48, slc6-i686/gcc49, centos7/clang39, centos7/gcc62, centos7/gcc7, fedora28/native, ubuntu16/native, mac1013/native, windows10/vc15 with flags -Dimt=ON -Dccache=ON
How to customize builds

@@ -174,5 +174,5 @@ public:
double Add(const TExampleClass &a, const TExampleClass &b);

} // namespace ROOT
#endif // #ifndef ROOT_RCodingStyle
#endif // ROOT_RCodingStyle
Copy link
Member

@amadio amadio Jul 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commenting on the commit message... Maybe a Suggested-by: tag in the body of the commit would be better?
There's a JIRA issue on me for the style of commit messages, maybe we should discuss this today too?

@phsft-bot
Copy link

Build failed on slc6/gcc48.
See console output.

Errors:

  • ERROR: Timeout after 30 minutes
  • ERROR: Error fetching remote repo 'origin'
  • ERROR: Error fetching remote repo 'origin'
  • ERROR: Timeout after 30 minutes
  • ERROR: Error fetching remote repo 'origin'
  • ERROR: Error fetching remote repo 'origin'

@phsft-bot
Copy link

Starting build on slc6/gcc48, slc6-i686/gcc49, centos7/clang39, centos7/gcc62, centos7/gcc7, fedora28/native, ubuntu16/native, mac1013/native, windows10/vc15 with flags -Dimt=ON -Dccache=ON
How to customize builds

@phsft-bot
Copy link

Build failed on slc6/gcc48.
See console output.

Errors:

  • ERROR: Timeout after 30 minutes
  • ERROR: Error cloning remote repo 'origin'
  • ERROR: Error cloning remote repo 'origin'

@phsft-bot
Copy link

Starting build on slc6/gcc48, slc6-i686/gcc49, centos7/clang39, centos7/gcc62, centos7/gcc7, fedora28/native, ubuntu16/native, mac1013/native, windows10/vc15 with flags -Dimt=ON -Dccache=ON
How to customize builds

@phsft-bot
Copy link

Starting build on slc6/gcc48, slc6-i686/gcc49, centos7/clang39, centos7/gcc62, centos7/gcc7, fedora28/native, ubuntu16/native, mac1013/native, windows10/vc15 with flags -Dimt=ON -Dccache=ON
How to customize builds

@phsft-bot
Copy link

Starting build on slc6/gcc48, slc6-i686/gcc49, centos7/clang39, centos7/gcc62, centos7/gcc7, fedora28/native, ubuntu16/native, mac1013/native, windows10/vc15 with flags -Dimt=ON -Dccache=ON
How to customize builds

@phsft-bot
Copy link

Build failed on centos7/clang39.
See console output.

Errors:

  • ERROR: Timeout after 30 minutes
  • ERROR: Error cloning remote repo 'origin'
  • ERROR: Error cloning remote repo 'origin'

@@ -0,0 +1,83 @@
/// \file RCodingStyle.cxx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes it makes sense to add \brief section which describes the contents and the purpose of the files.

// Parts of ROOT might want to use sub-namespaces for *internal* code.
// Such code might include the following two namespaces:
namespace Detail {
// Contains code that is not expected to be seen by the everage user.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo everage

@phsft-bot
Copy link

Starting build on slc6/gcc48, slc6-i686/gcc49, centos7/clang39, centos7/gcc62, centos7/gcc7, fedora28/native, ubuntu16/native, mac1013/native, windows10/vc15 with flags -Dccache=ON
How to customize builds

Comment on lines +69 to +71
ROOT::RExampleClass::~RExampleClass()
{
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not ROOT::RExampleClass::~RExampleClass() = default; ?

Comment on lines +45 to +66
// Include ROOT's headers first, in alphabetical order:
// Rationale: make sure that ROOT headers are standalone.
// Do not use #include guards at the point of `#include`.
// Rationale: compilers optimize this themselves, this is interfering with their optimization.
// Use <>, not "".
// Rationale: "" looks at ./ first; as ROOT headers are included by user code
// that adds context fragility.
#include <ROOT/TSeq.hxx>
// Include v6 ROOT headers last.
// You're welcome to state what's used from a header, i.e. why it's included.
#include <Rtypes.h> // for ULong64_t

// Now include other C++ headers hat are not from the stdlib:
// e.g. #include <cppyy/CPpYy.h>

// Include stdlib headers next, in alphabetical order.
#include <string>

// Include C headers last.
// Rationale: non-ROOT, non-stdlib headers often #define like mad. Reduce interference
// with ROOT or stdlib headers.
#include <curses.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if these rules could be automated via the IncludeCategories setting in clang-format.

/// Static functions line up alphabetically with the others.
static int GetSeq() { return kSeq; }

/// It is fine to have one-line function declarations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you mean function definitions.

/// \param[in] input A collection of strings to use.
/// \return Always return true but if it could fail would return false in that case.
///
/// All functions must have at least one line of comments, parseable/useable by doxygen.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds very strict to me. Simple functions with good names should not need comments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and disagree. One line of comment should be mandatory, because otherwise the docs look like this:
https://root.cern/doc/master/classTInterpreter.html

This one line should be one sentence, ending with a ., so doxygen automatically recognises this as a \brief.

I agree, though, that after having written a single sentence, you may leave out the rest for trivial functions.


/// Virtual destructors of derived classes may be decorated with `virtual` (even though
/// they "inherit" the virtuality of the virtual base class destructor).
virtual ~RCodingStyle() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably be virtual ~RCodingStyle() = default;.

/// \param[in] input A collection of strings to use.
/// \return Always return true but if it could fail would return false in that case.
///
/// All functions must have at least one line of comments, parseable/useable by doxygen.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and disagree. One line of comment should be mandatory, because otherwise the docs look like this:
https://root.cern/doc/master/classTInterpreter.html

This one line should be one sentence, ending with a ., so doxygen automatically recognises this as a \brief.

I agree, though, that after having written a single sentence, you may leave out the rest for trivial functions.

// that adds context fragility.
#include <ROOT/TSeq.hxx>
// Include v6 ROOT headers last.
// You're welcome to state what's used from a header, i.e. why it's included.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, this might be outdated the second time a file is touched.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fully agree!

}

/// Instead of static data members (whether private or public), use outlined static
/// functions. This solves the static initializion fiasco, and delays the initialization
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// functions. This solves the static initializion fiasco, and delays the initialization
/// functions. This solves the static initialization fiasco, and delays the initialization

};

///\class RCodingStyle
/// This is exhaustive documentation of the class template, explaining the constraints
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first thing after the \class macro should be the brief documentation. Doxygen takes the first sentence of the docs if no \brief is passed, so try to just write one sentence in one line that ends with a ..

///\class RCodingStyle
/// This is exhaustive documentation of the class template, explaining the constraints
/// on the template parameters, e.g.
/// `IDX` must be positive, `T` must be copyable.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend using doxygen's\tparam, e.g.:

Suggested change
/// `IDX` must be positive, `T` must be copyable.
/// \tparam IDX The index type. Must be positive.
/// \tparam T A class that is copyable.

RCodingStyle() = default;

// Open a group:
/// \{ \name copy pperations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// \{ \name copy pperations
/// \{ \name copy operations

// Parts of ROOT might want to use sub-namespaces for *internal* code.
// Such code might include the following two namespaces:
namespace Detail {
// Contains code that is not expected to be seen by the everage user.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Contains code that is not expected to be seen by the everage user.
// Contains code that is not expected to be seen by the average user.

Comment on lines +226 to +227
/// \param a - first RExampleClass to add.
/// \param b - second RExampleClass to add.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that doxygen generates better docs without the -:

Suggested change
/// \param a - first RExampleClass to add.
/// \param b - second RExampleClass to add.
/// \param a First RExampleClass to add.
/// \param b Second RExampleClass to add.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants