C++ coding guidelines

Discussion of chess software programming and technical issues.

Moderators: hgm, Dann Corbit, Harvey Williamson

User avatar
ilari
Posts: 750
Joined: Mon Mar 27, 2006 7:45 pm
Location: Finland

Re: C++ coding guidelines

Post by ilari »

abulmo wrote:
mar wrote:Forget about C++, it's flawed: http://yosefk.com/c++fqa/defective.html
Yes, but what else?

C is not an answer as C++ is a "better C".
Other languages all produce inefficient binary, and so are not good alternatives either.
C++ should not be thought of as better C - it's a different language and it should be used differently. Fruit is a good example of how to use C++ without really using C++, and Stockfish is a great example of how C++ should be used.

And not all code has to be fast. In a typical desktop application only a very small percentage of the code is performance-critical.
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C++ coding guidelines

Post by lucasart »

ilari wrote:
abulmo wrote:
mar wrote:Forget about C++, it's flawed: http://yosefk.com/c++fqa/defective.html
Yes, but what else?

C is not an answer as C++ is a "better C".
Other languages all produce inefficient binary, and so are not good alternatives either.
C++ should not be thought of as better C - it's a different language and it should be used differently. Fruit is a good example of how to use C++ without really using C++, and Stockfish is a great example of how C++ should be used.

And not all code has to be fast. In a typical desktop application only a very small percentage of the code is performance-critical.
+1
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C++ coding guidelines

Post by lucasart »

lucasart wrote:
ilari wrote:Google's C++ style guide is pretty good, and has good reasoning behind every rule.

One suggestion for your project's design would be to use composition instead of inheritance between the Engine and Process classes, ie. Engine should have a private member variable of type Process. That's how it's implemented in Cute Chess - the ChessEngine class has a QIODevice member which could be a process, a TCP socket, a file, etc.
Thank you Ilari. I will have a look at your link.

My rationale for the process base class, was that it has no dependancies, and can be extracted as is, and used in any other project that needs to spawn/kill child processes, and "talk" to them via stdin/stdout.

The most important thing for me is to find a good way to name my variables/class/functions. There is already a lot of inconsistency there, and I haven't found a systematic way of naming things :oops:
Regarding the Process and Engine class, on second thought, I think you're right. I can always have a Process class (generic and reusable), and have an instance of it as a member of the Engine class. After all the only virtual function is Engine::create(). Other than that, Engine and Process have nothing in common. Process is more of an API for Engine to use, than a base class that will have several class deriving from it and sharing some common properties.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: C++ coding guidelines

Post by Sven »

lucasart wrote:
ZirconiumX wrote:In My Stupid Opinion, maybe you could try to generate your own magics, or at least encapsulate the magic code in a class.

Matthew:out
I don't think class encapsulation is relevant in this particular case. Magic bitboards have a functional reality, not an object reality. Basically you have precomputed arrays, and 2 functions (bishop_attack and rook_attack). Encapsulating into a class is conceptually wrong, because an instance of that class doesn't make any sense. Why would I ever want to instantiate several Magic objects ? IMO the right way to encapsulate such things is to use a namespace, not a class.

This misconception (that everything should be encapsulated into a class) typically emanates from Java programmer.

As for generating my own magics, I really don't want to spend my time reinventing the wheel. I have enough things to do before I get something decent (comparable to Ilari's brillant cutechess-cli).

But yes, you have a fair point about encapsulation in general (class or namespace). I need to think about createing some (well chosen) namespaces.
A class having only static members serves roughly the same purpose as a namespace in this case. (You can find huge discussions about this, of course ...) It is clearly debatable which of the two concepts would be more appropriate, but both would be correct for your case. Personally I dislike namespaces for several reasons:

- they allow, and therefore invite to, distributing declarations of the same scope (namespace) over several (header) files which is impossible when using a class;

- they do not allow access specifiers ("public", "protected", "private"), everything is public so there is no encapsulation, no separation of interface and implementation;

- unlike class declarations, a namespace declaration does not end with a semicolon, a detail which I really hate :-)

There may be other arguments against classes with only static members, of course, and it is a matter of taste and - perhaps - discipline. If you choose namespaces for the purpose of encapsulating "magic bitboards" functionality then it is perfectly fine if you can accept the limitations I mentioned above.

Whenever something has a state that can change during the lifetime of a program I choose a class, even if it has only one instance. In single-CPU chess engines this might be "the board", "the game" or "the searcher" (where the latter is something like a machine that does some processing on demand and has an internal state while working). Also "the evaluator" can have an internal state. "The move generator" usually hasn't (but might have) so it may be a candidate for a namespace or a "static members only" class (sometimes also called a "module").


As to your question about naming, for me the most important points are:
1) be as consistent as possible, but without exaggerating heavily;
2) always imagine that someone else reads your code.
Everything else either derives directly from that, or is less important.

I can tell you my own naming rules, maybe you find 10% of these useful for you.

- Classes, types, namespaces and constants start with an uppercase letter;

- as an exception, typedef's to standard built-in types, like "typedef unsigned int uint;", start with a lowercase letter since they resemble built-in types;

- member functions, member variables, local variables start with a lowercase letter (not counting the prefix yet, see below);

- there are no "global" variables in own code, except for temporary debugging purposes;

- instance member variables have a prefix "m_" that helps to distinguish them easily from formal method parameters (some people use a suffix like "_" either for instance members or for parameters which is also fine, although I think that "m_" increases readability a bit);

- static member variables ("class members") have a prefix "c_";

- regarding use of mixed case vs. use of underlines, I mostly use mixed case but I don't consider that a religion;

- use longer names for almost everything with non-local visibility, like class names or member names;

- short or very short names can be appropriate for parameters and local variables denoting frequently occurring concepts; examples: "i", "j" for loop counters, "s" for square ids (square numbers), "b" for the board (reference to a board instance), "m" for a move, etc.;

- pointer variables start with a "p", in case of instance members with "m_p", in case of static members with "c_p";

- unlike other coding guidelines, mine do not contain a rule that defines something like "zero-terminated string variables start with 'sz', integer variables start with 'i', bools start with 'b'"; sometimes I use something like that but I feel it interferes with my understanding of readability;

- all classes and other types describing something that has a state and can be instantiated are named by a noun that describes one such instance (no plural);

- namespaces (if I use them at all, see above) and those classes having only static members usually are named by a noun that describes the domain (although I still tend to use the name "MoveGenerator" instead of "MoveGeneration");

- for member functions returning boolean attributes use a form like "isXX", "hasXX";

- for member functions returning other attributes (whether they are internally stored as member variables or indirectly derived from them) use the name of the attribute itself (some people use "getXX" which is also o.k. of course but it sounds a bit procedural for me);

- for member functions that modify something and/or do some processing, use a verb describing that activity (this may actually be the most difficult part when choosing good identifiers);

- for member variables and local variables use a name describing the value itself; in case of arrays use either the singular describing one element or a name describing the whole array, but no plural form since that might create irritation at the place of using array elements.

There may be more rules that I don't remember at the moment, but the ones given above are probably the most important ones for me.


Sven
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: C++ coding guidelines

Post by mcostalba »

Sven Schüle wrote: There may be more rules that I don't remember at the moment, but the ones given above are probably the most important ones for me.
One advice that I remenber becuase it is very funny but at the same time very true is: Don't name objects/class that end with 'er'

http://objology.blogspot.it/2011/09/one ... dvice.html
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: C++ coding guidelines

Post by Don »

mar wrote:Forget about C++, it's flawed: http://yosefk.com/c++fqa/defective.html
Digital Mars D, I am keeping an eye on it. It's way better for programming than C++ but I'm not ready to take the plunge. It has the potential to be faster than C for execution, but it's slightly slower. It doesn't have the wide platform exposure of C or C++ and it's still not clear if it's here to stay - but it looks like it is being integrated into the gcc stuff.

Don
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: C++ coding guidelines

Post by Rein Halbersma »

ilari wrote:Google's C++ style guide is pretty good, and has good reasoning behind every rule.

One suggestion for your project's design would be to use composition instead of inheritance between the Engine and Process classes, ie. Engine should have a private member variable of type Process. That's how it's implemented in Cute Chess - the ChessEngine class has a QIODevice member which could be a process, a TCP socket, a file, etc.
The Google C++ coding style is certainly well thought out, but also a little outdated IMO. E.g. it does actively discourage (i.e. forbid) the use of modern language features (exceptions, all C++11 stuff) and libraries (e.g. Boost). My favorite guidelines are from the Alexandrescu & Sutter book .
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: C++ coding guidelines

Post by Rein Halbersma »

mcostalba wrote:
lucasart wrote: Also, I need to make the code more self explanatory, by using self-obvious and consistent naming conventions
Naming is one of the most difficult thing to get it right, of course it is not related to C++ but it is common for any language. It requires a lot of "sensibility" and a lot of clearness of mind: if you know exactly what you are doing your naming will be better than if you have a more or less focused idea or don't understand completely the subject.
The same applies to commit messages: I find the Stockfish style of commit messages really exemplary in their clearness and conciseness. For my own code, I fall all too often victim to messages such as "small fixes all over the place", or "minor cleanup" etc., which are the equivalent of naming classes "DataInfoManager" or "GenericObject" and other non-informative noise. Looking at other open source projects, I find it more often the case than not that even the most disciplined coders -who are very careful with naming their functions and classes- often get sloppy when committing their work :(
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: C++ coding guidelines

Post by Rein Halbersma »

Sven Schüle wrote: A class having only static members serves roughly the same purpose as a namespace in this case. (You can find huge discussions about this, of course ...) It is clearly debatable which of the two concepts would be more appropriate, but both would be correct for your case. Personally I dislike namespaces for several reasons:

- they allow, and therefore invite to, distributing declarations of the same scope (namespace) over several (header) files which is impossible when using a class;

- they do not allow access specifiers ("public", "protected", "private"), everything is public so there is no encapsulation, no separation of interface and implementation;

- unlike class declarations, a namespace declaration does not end with a semicolon, a detail which I really hate :-)

There may be other arguments against classes with only static members, of course, and it is a matter of taste and - perhaps - discipline.

Sven
The distributed header argument is not that compelling because the interface of a class (i.e. the scope of ADL in C++) also consists of the functions taking parameters of that class, and these functions are often spread out over several headers for the same reason that namespaces are spread out: build-time optimization and modularity.

One other argument in favor of classes: templates. It's much more convenient to template a single class of static functions than to template every function inside a namespace, especially when doing specializations.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: C++ coding guidelines

Post by Sven »

Rein Halbersma wrote:
Sven Schüle wrote: A class having only static members serves roughly the same purpose as a namespace in this case. (You can find huge discussions about this, of course ...) It is clearly debatable which of the two concepts would be more appropriate, but both would be correct for your case. Personally I dislike namespaces for several reasons:

- they allow, and therefore invite to, distributing declarations of the same scope (namespace) over several (header) files which is impossible when using a class;

- they do not allow access specifiers ("public", "protected", "private"), everything is public so there is no encapsulation, no separation of interface and implementation;

- unlike class declarations, a namespace declaration does not end with a semicolon, a detail which I really hate :-)

There may be other arguments against classes with only static members, of course, and it is a matter of taste and - perhaps - discipline.

Sven
The distributed header argument is not that compelling because the interface of a class (i.e. the scope of ADL in C++) also consists of the functions taking parameters of that class, and these functions are often spread out over several headers for the same reason that namespaces are spread out: build-time optimization and modularity.
Here I disagree with Herb Sutter, the author of the page you linked to. In my view functions taking parameters of a class are *not* part of the interface of that class, they only use it but are outside. But here we enter an area of opinions, so let's just agree that we have different ones ;-)
Rein Halbersma wrote:One other argument in favor of classes: templates. It's much more convenient to template a single class of static functions than to template every function inside a namespace, especially when doing specializations.
Agreed. I missed that argument in my list above.

Sven