Taichi: Code formats and how to enforce them

Created on 2 Mar 2020  路  9Comments  路  Source: taichi-dev/taichi

We are currently making use of automatic tools (clang-format and yapf) to (weakly) enforce C++ and Python code format. Starting from v0.6.0, we want to strictly enforce code format. A few topics on this:

Actions

  • We are considering adding a githook to make sure any modified file is processed by clang-format and yapf

    • Pro: code will always get formatted before committing

    • Con: every developer has to install the tools. Also git commit may take a few seconds longer

  • Is there an available online "CI" service that check for code format? If so we should also set that up in case anyone's code is not properly formatted

Code styles

(It's hard to come up with a code style that makes everybody happy and I believe as long as we follow a set of consistent rules, then we are good.)

C++: we are using a clang-format profile that mostly follows the 'Chromium` code style

Header orders (following Google's C++ style guide) as suggested by @k-ye:

  • #include <...> only for standard libraries
  • #include "..." for everything else. No relative paths allowed: even Taichi headers must use the full path starting with "taichi/..."

Python: The python code format is simply Chromium style

I suggest that we just stick to these styles unless there's a solution that's significantly better. What do you guys think? :-)

Additional comments

Should we also make use of linting tools such as cpplint to statically check for potential bugs/bad patterns?

Inputs are welcome!

discussion

All 9 comments

Usually people can do style well with self-dicipiline, having a githook on this really just slow down time for us, if we want we can run ti format by hand.
For newcomers, we may want to add this style infomation to Contribution Guideline? If one don't follows the style, we reviewers can run ti format before merge, and mind them for the next time :)

instead of giving https://github.com/taichi-dev/taichi/blob/master/.clang-format, I think have some sample codes is more friendly to people:

int foo() { // all `{`'s follow last line, function name is in the same line of return type declaration
  int x = 1; // tab=2, expanded in space
  if (x == 4) // space after controling keywords like `if`
    return x + 233; // having spaces before and after operators
}

Yeah, being self-discipline is good yet inevitably people (including me myself) may accidentally commit style-violating code. Actually, a well-done git hook should work on the files changed only, and will not take more than 5 seconds per commit. So I would still lean towards having a githook.

instead of giving https://github.com/taichi-dev/taichi/blob/master/.clang-format, I think have some sample codes is more friendly to people

Yeah maybe we should also have a minimal sample file in Contributor Guidelines. CLion has a small piece of code that covers many C++ constructs, which we can make use of:

#if !defined(OS)
#define OS_NOT_DEFINED
#endif

/*********************************************
* ...globalFunc...
*********************************************/
void globalFunc();

namespace foo {
  /**
  ...Foo...
  */
  class Foo {
  public:
    Foo();

    ~Foo();

    virtual Foo *getSelf() { return Foo::getSelf(); }

  private:
    void innerFunc();

    int var;
  };
}
struct FooPOD {
#ifdef OS_NOT_DEFINED
#define OS "unknown"
#endif
#define FooPOD_OS OS
  int i;
};
struct FooC {
private:
  int i;
};
extern int a;

static int innerFunc();

int a = innerFunc();

int innerFunc() { return 5; }

void foo::Foo::innerFunc() {
  label1:
  int continuation = 0xCD
                     + 0xFD + 0xBAADF00D + 0xDEADBEEF;
  auto la = [](int i1, int i2) -> bool mutable {
    label2:
    return i1 < i2;
  }(1, 2);
}

we reviewers can run ti format before merge, and mind them for the next time :)

That's a good idea - we don't want code styles to stop people from contributing.

#ifdef/ifndef x, #if !x or #if !defined(x)? Please choose one, it seems we are mainly ifndef for now.
Was virtual Foo *getSelf() { return Foo::getSelf(); } expected? Less than 80 chars so it can be inlined?

label1:
  int continuation = 0xCD

Some compilers don't like labels to be followed by variable declaration, please tell them to use label1:; instead, or completely give up goto (which is used by many devs).

#ifdef/ifndef x, #if !x or #if !defined(x)? Please choose one, it seems we are mainly ifndef for now.
Was virtual Foo *getSelf() { return Foo::getSelf(); } expected? Less than 80 chars so it can be inlined?

label1:
  int continuation = 0xCD

Some compilers don't like labels to be followed by variable declaration, please tell them to use label1:; instead, or completely give up goto (which is used by many devs).

Let's use #if !defined(x).

This is just a piece of sample code trying to cover as many language constructs as possible. Clearly we don't need every part, for example, the labels for goto.

It seems that we can make use of Github actions to automatically check formats of PRs: https://github.com/marketplace/actions/clang-format-lint

Merged into #592

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xumingkuan picture xumingkuan  路  3Comments

g1n0st picture g1n0st  路  3Comments

zdxpan picture zdxpan  路  3Comments

archibate picture archibate  路  3Comments

liaopeiyuan picture liaopeiyuan  路  3Comments