Author Topic: Project Conventions  (Read 6806 times)

daniel.santos

  • Guest
Project Conventions
« on: 25 September 2009, 19:51:02 »
We've discussed this a lot and since I have more to say on it, I thought a nice topic devoted to it would be in order.  That way, we can argue about discuss it and have it all in one place! :)  After we come to agreement, let's post this on Wikia.  So here's what I propose (I have to do this as a table because I can't get it to format correctly otherwise :( ):

1.Copyright headers.  I have no problem with Glest's original copyright headers.  If you make significant modifications to a file (like converting xml_parser to TinyXML or some such) please add yourself to the copyrights (I think most of you have been).
2.Wrap after 100 spaces.  The classic standard is to not exceed 80 characters per line.  With the wide availability of huge monitors (mine is 1920x1200 and these aren't too expensive now days) combined with the increasing practice of using long identifier names, I think that expanding this 100 is very reasonable.
3.Configure your code editor to trim trailing spaces.
4.K&R code formatting, but with the below exceptions (and/or clarifications):
5.Indent only with tabs (and use 4 spaces for tabs)
6.Attach braces please:
Code: [Select]
if (jack > jill) {
    jill += jack;
} else {
    jack += jill;
}
7.I don't like having spaces inside of parenthesis, can we argue about discuss this more pleeeease??? :) :)
8. A space around all operators, except preceding a comma.  This includes the asterisk when used for multiplication, but not when used as part of a type name.  This also excludes function call operators . and ->
9.Use Doxygen compatible comments, prefer Javadoc-style (that's my preference -- if you aren't already very attached to any other Doxygen comment style, then I insist on it!! :) )  I personally vote to (optionally) use Qt-style same-line comments for global variables, C++ data members and enums where appropriate (but the Javadoc variant).  Example:
Code: [Select]
class Lang {
private:
    string locale;        /**< Should have this format: language[_territory][.encoding][@script] */
// ...
}
I'm not hard-set on this one, especially if you want to have a much longer explaination, I think we should have the option of using the standard:
Code: [Select]
class Lang {
private:
    /**
     * Really really long explaination...
     * blah blah blah
     * blah blah blah
     */
    string locale;
// ...
}
10.Redundancy sucks.  Last year (in the network re-write), I moved the glest_game to game and the glest_map_editor to map_editor.  I also eliminated the "Glest" C++ namespace.  I've finally moved the diretory changes into the 0.2.13 branch, but not the namespace changes.  
11.Namespaces are good (when used correctly).  In the network branch, I've moved all of the network code into Game::Net.  I wouldn't mind if we organized things into more namespaces (like types, type_instances, etc.).  For me, this also helps me to find the classes I want in my class browser more quickly (since it groups them by Namespace).
12.Getters & Setters.  When getters & setters are very short and sweet, I like them in Martiño's classic format, with one difference, use the parameter name "v" in setters -- that way, you don't have to prepend this-> to your data member name and it makes the whole thing shorter, cleaner & more readable.  The name of the parameter isn't important in this case because we know from the function name what the subject is.  So here's a re-cap on that:
  • Group all getters & setters in one place (if it's a large class with lots of boolean getters/setters, group the booleans together as well).
  • Keep the function bodies prettily aligned.  Use tabs for this alignment. Keep the intention level of the function bodies aligned within each section.
  • Use the parameter name of "v" in classic (single argument) setters for brevity & simplicity.  A real parameter name is not necessary in these cases because the it's in the name of the function, thus adding nothing to clarify, while forcing the use of this-> in the function body, etc.
  • Declare getter member functions const unless there's a very good reason not to.  If the getter cannot be declared const because of some implementation issue, but still behaves as const (i.e., doesn't really modify the object), consider using const_cast<MyClass*>(this)-> in the getter and make the function const anyway.  If both a const and non-const getter is needed, consider using const_cast from the const getter to call the non-const.
  • No padding braces with spaces.
13.When adding new text files to subversion, always svn propset svn:eol-style native <filename>
14.I wish we had a button in the forum message edit toolbar or a custom [snippet] tag that was the equivalent to the following, because it sure makes it easier to distinguish code (but is a pain to insert)
Code: [Select]
[glow=lightgrey,2,300][tt]text[/tt][/glow]
15.Source file character encoding: ISO 8859-1? EDIT: I'm starting to think that UTF-8 would be better as it would be more fair to developers who may join in the future, but who's name contains characters not included in 8859-1.  Additionally, it may be a more common standard.
16.In constructors, prefer member initializers to assignments in the ctor body.  Using member initializers results in both smaller & faster code and they exist for this purpose.  The ctor body is supposed to be for general purpose functionality or something that you can't do in an initializer for some reason.
17.Format of constructors.  This is what I recommend at this moment.
Code: [Select]
MyClass::MyClass(int param1, const string &param2)
        : MyBaseClass(param1)
        , dataMember1(param2)
        , dataMember2("itchy")
        , dataMember3("butt") {
    // whatever goes in the body
}
I'm not dead set on the indentation, I *could* possibly be open to only indenting the initializers once.  However, double indentation helps clarify the initializers from the ctor body (which is important when attaching braces).
18.With every release, we do the following (and we gotta script this as much as possible)
  • Generate API docs
  • generate installer
  • run automated tests
  • run automated announcements (freshmeat.net, etc)
  • change version numbers (we need better automation for this too)
19.Class declaration format.  Here's the format I would like to use:
Code: [Select]
class MyClassName {
// nested typedefs, enums & classes

// static data members

// data members

// static functions here?  (or maybe after ctors/dtors?  or maybe keep them with static data members?)

// ctors/dtors

// overloaded operators

// getters & setters

// all other member functions
};
I'm thinking we should explicitly include the "public:", "protected:" or "private:" at the begenning of each of the 1st sections, at least up until ctors/dtors, even if it's already set in the previous section, perhaps more as a way to demarcate sections.  Alternately, maybe we can just start using some type of header for each section (strictly comments)?  I just want it to be clear where each section begins & ends.  I also don't want to be too strict about what happens after ctors/dtors, but I think the order above is a descent guideline.  I know it's a common practice to put data members last, but I prefer to see them prior to functions.  Despite OO ideology, I still perceive classes as being defined more by their data than their interfaces.
20.Use ALL_UPPER_CASE for values that are either #defined, enum, const globals or static const data members.  Silnarm & I have been discussing a new way to scope enums within classes and eliminating the standard scope prefix (i.e., BlendFunc values being BlendFunc::SRC_ALPHA and BlendFunc::SRC_ALPHA_MINUS_ONE instead of BLEND_FUNC_SRC_ALPHA and BLEND_FUNC_SRC_ALPHA_MINUS_ONE), but we're not finished with it.
21.Prefer object references to pointers.  The general exclusion to this is when an objects may or may not exists (i.e., be NULL) and then you have to have a pointer.
22.Prefer passing const reference to passing objects.  I think that one is a general no-brainer, but it's worth having in the standards, IMO.  I also prefer to pass 64-bit values (double and long long/int64) as const reference because (I believe) it generates less instructions on a 32 bit machine and results in the same number of instructions on a 64 bit machine (but maybe I'm wrong :) )
23.In *general*, when a line exceeds 100 characters and you break it, double indent.  This helps distinguish wrapping from code blocks.  Break this rule only if you think you can make it significantly prettier.  e.g.
Code: [Select]
   str << "some stuff" << someVale << "lots more stuff"
        << "more stuff" << someVale << "lots more stuff"
        << "more stuff" << someVale << "lots more stuff";
24.Break the "tabs only for indentation & alignment" rule where code can be made prettier by doing so.  Example:
Code: [Select]
           bool anySubmerged = getSubmerged(getTile(x, y))
                    || (x + 1 < tileW && getSubmerged(getTile(x + 1, y)))
                    || (x - 1 >= 0    && getSubmerged(getTile(x - 1, y)))
                    || (y + 1 < tileH && getSubmerged(getTile(x, y + 1)))
                    || (y - 1 >= 0    && getSubmerged(getTile(x, y - 1)))
                    || (x + 1 < tileW && y + 1 < tileH && getSubmerged(getTile(x + 1, y + 1)))
                    || (x + 1 < tileW && y - 1 >= 0    && getSubmerged(getTile(x + 1, y - 1)))
                    || (x - 1 >= 0    && y + 1 < tileH && getSubmerged(getTile(x - 1, y + 1)))
                    || (x - 1 >= 0    && y - 1 >= 0    && getSubmerged(getTile(x - 1, y - 1)));
I converted everything to spaces to display it correctly on the forums, but in the sources, it's a mixture of tabs & spaces to keep the width down and still have everything aligned prettily (which is more readable).  (As a side-note, this code is commented out in favor of an alternate implementation.)
25.Never copy files in the repository without using svn copy or svn merge!!!!!!
In order words, don't copy files on your local machine, create a branch and then add them.  This will will make subversion think that the files are completely new and subsequent merges will be hell, because there is no revision history or common ancestry.
xxxxxx

That's all I can think of for now, I'm sure I'll have more later.

Questions:
  • When should we merge with the trunk?  Whenever we release?

EDIT: Added more stuff.
EDIT2: Edited list and added more items to it.
EDIT3: Added more items
« Last Edit: 29 September 2009, 18:19:07 by daniel.santos »

daniel.santos

  • Guest
Re: Project Conventions
« Reply #1 on: 25 September 2009, 21:38:53 »
Oh, also, character encoding of source files: ISO 8859-1?

Omega

  • MegaGlest Team
  • Dragon
  • ********
  • Posts: 6,167
  • Professional bug writer
    • View Profile
    • Personal site
Re: Project Conventions
« Reply #2 on: 25 September 2009, 21:51:12 »
Fully agree with doxygen style comments. On that note, what is the link to GAE's doxygen documentation on codemonger.org? I know there is one (stumbled upon it once), but dunno the link...

6. I'm not sure about that style of braces. I've always though that this was easier to read:
Code: [Select]
if (jack > jill){
    jill += jack;
}
else{
    jack += jill;
}
Just a simple line break after each end brace.

7. What's wrong with spaces inside parathesis? Don't you mean spaces like ((jack / jill) + 2) or do you mean function( )? Spaces SHOULD be kept when using parathesis such as in a mathmatic equation for easier readability (some parsers automatically do this), but in a function that does not need any variables passed, then it shouldn't have a space.


Personal test to see what your 'code' format for the forums was:

#include <iostream>

int main()
{
   std::cout << "Hello, world!";
}


Hmm, I dunno. What's wrong with the {code} {/code} tags? Or did I do it wrong? The ability to have a fixed size with the scrollbars for overflow is much better IMHO.
Edit the MegaGlest wiki: http://docs.megaglest.org/

My personal projects: http://github.com/KatrinaHoffert

daniel.santos

  • Guest
Re: Project Conventions
« Reply #3 on: 25 September 2009, 22:32:58 »
Fully agree with doxygen style comments. On that note, what is the link to GAE's doxygen documentation on codemonger.org? I know there is one (stumbled upon it once), but dunno the link...

Well that gives me another idea: Generate API docs with every release.  I haven't updated them in a while: http://glest.codemonger.org/docs/gae/

6. I'm not sure about that style of braces. I've always though that this was easier to read:
Code: [Select]
if (jack > jill){
    jill += jack;
}
else{
    jack += jill;
}
Just a simple line break after each end brace.

Yikes! I almost blew an artery!

7. What's wrong with spaces inside parathesis? Don't you mean spaces like ((jack / jill) + 2) or do you mean function( )? Spaces SHOULD be kept when using parathesis such as in a mathmatic equation for easier readability (some parsers automatically do this), but in a function that does not need any variables passed, then it shouldn't have a space.

Both, I prefer ((jack / jill) + 2) and climbHill(jack, jill * (bucket - 14)).  I can see the benefit from adding extra spaces around parenthesis, especially when it gets deeply nested.  However, most code editors will highlight the opposing parenthesis for you, making it easier to read rather or not it had spaces around it.  I'm willing to discuss this, I'm just both not used to it and not certain it provides a real readability benefit.

Hmm, I dunno. What's wrong with the {code} {/code} tags? Or did I do it wrong? The ability to have a fixed size with the scrollbars for overflow is much better IMHO.
Oh no, I'm not talking about not using the [ code ] tags, I'm talking about for smaller amounts of text that you don't want to put in a [ code ] block (like in a sentence).

daniel.santos

  • Guest
Re: Project Conventions
« Reply #4 on: 25 September 2009, 22:53:20 »
Additional clarifications:  A space around all operators, except preceding a comma.  This includes the asterisk when used for multiplication, but not when used as part of a type name.  This also excludes function call operators . and ->

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Project Conventions
« Reply #5 on: 26 September 2009, 03:01:19 »
3. Doesn't seem like a good idea from what I've been reading, and it's not possible without a macro in VS.
http://stackoverflow.com/questions/82971/how-to-automatically-remove-trailing-whitespace-in-visual-studio-2008
http://billfellows.blogspot.com/2009/05/strip-trailing-spaces-on-save-in-visual.html

5. the amount of spaces is user independant, as long as it's not committed in a project file if they store those sort of options in there.

6. In some cases I've put the else on a separate line because it's easier to read. (eg in MenuStateRoot::mouseClick)

7. I'm fine either way.

8. Could say mathimatical operators. I don't remember a comma ever being used as an operator.

15. should be ok. http://en.wikipedia.org/wiki/ISO/IEC_8859-1

17. I have been using this for the gui code which uses lots of member initializers and it's much better. Stick with double indenting.

18. Some other possible activities on release:
  • generate installer
  • run automated tests
  • run automated announcements (freshmeat.net, etc)
  • change version numbers

Merge with trunk whenever the branch is ready (ie functionally complete and hopefully tested sufficiently). I'm using the Feature Branches pattern but I think you are wanting something more like the Release Branches pattern. http://svnbook.red-bean.com/en/1.5/svn.branchmerge.commonpatterns.html

Additional Items
- How to deal with platform dependant code?
- Using const instead of define.
- Use reference instead of pointers where possible?
- https://docs.megaglest.org/GAE/CodingConventions#Code_Organisation
- https://docs.megaglest.org/GAE/CodingConventions#Debug_.23defines
« Last Edit: 18 June 2016, 19:00:08 by filux »
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Project Conventions
« Reply #6 on: 26 September 2009, 03:33:19 »
Let the argument discussion commence!  :P

I'm happy with most of that, with a few exceptions of course :)

I like a bit of space, and personally do feel it improves readability, but then this is probably something that's tied significantly to what you are used to. In particular I like space before, in and after a logical test, if ( myBool != yourBool ) { but have been using no space before a parameter list, as Hailstone suggested a while back, result = someFunction( param1, param2 );.  Obviously with no space in an empty parameter list.

And I'm right with Omega on the if/else thing, indeed I feel kind of strongly about it! When I see an 'else' I want to also see an 'if' or 'else if' directly above it, at exactly the same indent level.  I don't like the waste of a line, but I can't stand things 'hanging out' like that, in between two indent levels...

8. Could say mathimatical operators. I don't remember a comma ever being used as an operator.
You've seen commas in code, so you've seen it used as an operator :), () is an operator too!
I think 'arithmetic and logical' operators should cover us for this one.

Quote
17. I have been using this for the gui code which uses lots of member initializers and it's much better. Stick with double indenting.
Agreed, I really like the double indent, and the comma at the start inline with the ':'

Something else I've been meaning to bring up...
theSingleton
This is something I've started using in the path finder branch, I like it... I would like to recommend its use, this is my list so far (probably reasonably complete now)
Code: [Select]
// game_constants.h

// The 'Globals'
#define theGame (*Game::getInstance())
#define theWorld (World::getInstance())
#define theMap (*World::getInstance().getMap())
#define theCamera (*Game::getInstance()->getGameCamera())
#define theGameSettings (Game::getInstance()->getGameSettings())
#define theGui (*Gui::getCurrentGui())
#define theConsole (*Game::getInstance()->getConsole())
#define theConfig (Config::getInstance())
#define thePathManager (*Search::PathManager::getInstance())
#define theRenderer (Renderer::getInstance())
#define theNetworkManager (NetworkManager::getInstance())
#define theSoundRenderer (SoundRenderer::getInstance())
#define theLogger (Logger::getInstance())

...and I also recommend whenever you see a Map*, World* or Game* being passed as a parameter, or stored as a data member, eliminate it! Do not pass any of the things around as parameters, and don't store pointers/references to them.
« Last Edit: 26 September 2009, 03:38:54 by silnarm »
Glest Advanced Engine - Code Monkey

Timeline | Downloads

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Project Conventions
« Reply #7 on: 26 September 2009, 04:13:05 »
Don't go overboard with the Singleton pattern. Unless there's a good reason to prevent multiple copies you shouldn't need it (although storing a global reference to it should be ok). I think this is something mentioned in the Effective C++ book or was it my uni lecturer  :-\. Also what's with all the defines?
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Project Conventions
« Reply #8 on: 26 September 2009, 05:06:33 »
Don't go overboard with the Singleton pattern. Unless there's a good reason to prevent multiple copies you shouldn't need it
I don't think a good reason to prevent multiple copies is needed, if there's only going to be one, and it's a heavy use object, make it a singleton.  This is a game, full of complicated systems working very closely with each other, I don't think we need to complicate it further by using 'good' design principles.

It may not be needed, but it makes life much easier... and again, this is a Game, so whatever your uni lecturers or software engineering texts have to say, it doesn't necessarily apply here :)

Quote
Also what's with all the defines?

Well,
theWorld.getThisTeamIndex();
is a bit nicer than
World::getInstance().getThisTeamIndex();
yes?
Glest Advanced Engine - Code Monkey

Timeline | Downloads

daniel.santos

  • Guest
Re: Project Conventions
« Reply #9 on: 26 September 2009, 05:24:06 »
Hurray, thanks for all of the responses!

3. Well, the problem with it is that it can "change" code when you don't mean to. :(  This problem is eliminated if everybody's editor does it, but you're right about MSVC++. :(  That's not a big one for me.

6. I guess this goes hand in hand with something else important I left out, and that's never exclude braces from a branch, even when the block will only contain one instruction.  The reason for this is that it prevents a very common mistake:

Programmer #1 writes some code:
Code: [Select]
    while (fred) {
        if (jack == jill)
            jack += 1;
    }

Then, Programmer #2 edits the code, but fails to notice the lack of braces or mistakes the closing brace of the while loop for the closing brace of the if:
Code: [Select]
    while (fred) {
        if (jack == jill)
            printf("jack=%d\n", jack);
            jack += 1;
    }

Suddenly, the meaning of the code changes dramatically.  So when braces are always used for all branches, you will never see an else in the code unless it looks like one of these two:

Code: [Select]
    if (jill) {
        jill += 1;
    } else if (jack) {
        jack -= 1;
    } else {
        jill = jack = 0;
    }

Thus, it becomes both consistent and symmetrical.  For me, I see the entire sequence of characters } else { as one operator because I always use them together.  However, improper or inconsistent indentation will blow its readability right out of the water because it depends upon indentation to visually demarcate code blocks.  I don't want to be rigid or demanding, but I also have a lot invested in this project, (even if I was absent for a while).  What is perhaps most important is that the formatting is consistent and that if we're going to make a change from a pre-existing format that there is consensus on it so we don't have multiple people pulling in different directions.  I've worked on a lot of other people's code over the last 15 years and the most frustrating is when it's inconsistent.

7.  I'm sorry, I've been trying it out and it drives me nuts, lol!! :)  I don't think the if's bother me as much as the function calls, but again, I tend to depend upon the code editor highlighting the opposing parenthesis.  I'm not used to adding a space between the if and the open-paren, but I find this very helpful and I'm trying to get in the habit of doing it (and I have my code formatter setup to do it).   :'(

8. Ahh, good summary Silnarm! :)

17. Yea, the colen and comma at the start of the line is something I just picked up earlier this year and really liked! :)

Regarding Mr. Singleton, it looks a bit cleaner, but I have to soak it in.  I agree with hailstone about avoiding the overuse of the Singleton pattern, but all of these singletons are already in existence.  The only place I have to disagree is for parts of the code dealing with changes in the program state where theWorld, theMap, theGame, etc may not be valid (because they only come into existence when a game is created), or in areas of the code that may be active when these are not alive.  Other than that, it seems sane and may be a really good idea.  But I have to soak it in. :)  In fact, it may be worthy of it's own topic.

Also, keep in mind that Singletons tend to make a program's structure very rigid and makes it harder to implement unit tests that execute your code in a different environment, and often restricts the order of object creation beyond what is necessary.

Then there are two more that I think you guys know already and that's:
18. Prefer object references to pointers.  The general exclusion to this is when an objects may or may not exists (i.e., be NULL) and then you have to have a pointer.
19. Prefer passing const reference to passing objects.  I think that one is a general no-brainer, but it's worth having in the standards, IMO.  I also prefer to pass 64-bit values (double and long long/int64) as const reference because (I believe) it generates less instructions on a 32 bit machine and results in the same number of instructions on a 64 bit machine (but maybe I'm wrong :) ).

daniel.santos

  • Guest
Re: Project Conventions
« Reply #10 on: 29 September 2009, 18:52:45 »
Nested pre-processor statments
I prefer for nested #ifs to be indented in some fashion.  I've seen a number of different methods for doing this and I'm curious on you guy's take.  Lately, I've been using this one, with tabs between the '#' and the rest of the statement (spaces used below for forum posting, but tabs used in code):
Code: [Select]
#if something
#   define something

#   if something_else
#       include "somesuch.h"
#   endif
#endif

A lot of GNU stuff uses two spaces for all of its indentation and thus, uses this style (only spaces used):
Code: [Select]
#if something
#  define something

#  if something_else
#    include "somesuch.h"
#  endif
#endif

There is the method of just indenting the entire statement, including the # sign.  I've had more than one code editor object to this and every time I've typed a # at the beginning of a line, it has automatically out-dented it.  I also don't think that I find this particularly visually appealing.
Code: [Select]
#if something
    #define something

    #if something_else
        #include "somesuch.h"
    #endif
#endif

As a final note, gcc appears to not mind when you start a line with # followed by either nothing else or just whitespace/comments:
Code: [Select]
#if something
#   define something
#
#   if something_else
#       include "somesuch.h"
#   endif
#endif

For solid blocks of pre-processor stuff, this feels cleaner when you want a line break, but my editor always wants to highlight it red, as if it were an error and I'm not certain that other compilers support it so I haven't been using (iirc).

Switch statements
To be honest, I really don't care much rather or not cases are indented in switch statements and since I'm so fussy on other issues, I would like to do what you guys prefer:

Not indented:
Code: [Select]
   switch (something) {
    case 0:
        someFunc();
        break;

    default:
        someOtherFunc();
    }

Indented:
Code: [Select]
   switch (something) {
        case 0:
            someFunc();
            break;

        default:
            someOtherFunc();
    }

Finally, this is what I've been doing when code for a case needs to be enclosed in a block (using indented case):
Code: [Select]
   switch (something) {
        case 0: {
            someFunc();
            break;
        }

        default:
            someOtherFunc();
    }

Do you guys have any preferences on how these are formatted?

Beautifiers
I've been researching beautifiers recently.  As with the times I've researched them before, I find them still lacking in all of the areas that I would hope for.  Thus, I'm considering modding astyle (a popular beautifier) to do the things I want it to do.  My idea is that if our differences in the formatting of else statements is going to be untenable, then we can use subversion scripts to modify the code formatting upon checkout (for those who like it differently) and then revert the format upon check-in.  As I've started this project and worked a lot to convert the format, I'm very insistent on some certain things (I'm just like that, sorry).  But I don't want to chase other talent away with my standards! :)  In order for this to work, we would need a beautifier that can respect our coding standards and not screw up things.  As such, I would probably mod astyle (or possibly another beautifier) and add options for it to do the things we've decided upon, are using, etc..  Specifically:
  • Martino's original style for inline definitions of small functions (getters & setters, etc.) where several functions are defined & implemented with no line break in between them, thus forming a group of inline functions.  Then, the bodies of these functions are all indented to the same column so that they are prettily aligned.
  • I haven't seen any beautifiers that support the style for implementing constructors with initializers formatted as we've discussed and I would like to see this.
  • Support for pre-formatted code that we don't want it to screw with, like stuff that looks prettier if we pad it so that things line up on multiple lines (like my example from #24 above or silnarm's Vec2i arrays in path_finder.h).  I dunno if we would have to have some mechanism to tell the beautifier (like an opening and closing comment) not to screw with the code or if we can modify the beautifier to figure out when it shouldn't screw with it.  Either way, without this, the svn scripting idea probably wont work very well (unless we use diffs or something, and that'll make the svn script it more complicated)
  • astyle sucks at detecting when an asterisk is being used for a type and when it's being used as binary operator (a.k.a., "multiplication operator").  I hate that it fails to add spaces around them usually when they are being used as binary operators.
  • astyle doesn't seem to support the "double intend when wrapping a statement" concept and tries to align it based on what it thinks is pretty

Obviously, I don't want to spend so much time on this that nothing *important* gets done in the game. :)

Finally, as a side note, I've discovered that the style I'm using is better defined as "Java" style rather than K&R, the big difference being that K&R doesn't attach braces for function definitions, but attaches them everywhere else, e.g.:

Code: (K&R Style) [Select]
void func()
{
    if (something) {
        thing = some;
    } else {
        some = thing;
    }
}

astyle's --style=java option is what defines the style I've been using.  I guess that's not a surprise, as I've done more Java than I have C or C++.
« Last Edit: 29 September 2009, 18:58:19 by daniel.santos »

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Project Conventions
« Reply #11 on: 29 September 2009, 23:00:00 »
Nested pre-processor statments
As a final note, gcc appears to not mind when you start a line with # followed by either nothing else or just whitespace/comments:
I believe there is some C compatibility thing at work here, and that this is indeed 'safe'. 
I like to indent, with the hash at the start of the line (though this is probably more from habit, when I was a youngster most compilers I used required it).

Along these lines, I think we should change our debug 'ifdef' conditions to 'if'.  Then leave them always defined (in the project settings for vc, Jamrules for jam) and turn them on/off by defining as 0 or 1 (or turn on to a certain 'level' with that number).

Code: [Select]
DEBUG_OVERLAYS=1
DEBUG_RENDERER_VISIBLEQUAD=1
DEBUG_SEARCH_TEXTURES=0

Or...

-DDEBUG_OVERLAYS=1
-DDEBUG_RENDERER_VISIBLEQUAD=1
-DDEBUG_SEARCH_TEXTURES=0

Quote from: daniel.santos
Switch statements
Do you guys have any preferences on how these are formatted?
Probably prefer to have them indented, but this one doesn't bother me either, switch statements are fairly distinctive anyway.

Quote from: daniel.santos
Beautifiers
Yeah, I don't want to be wasting to much time with this sort of thing.  I don't like the hanging else, but I can live with it, and am happy to do so :)  So please don't spend time hacking astyle to try and keep everyone completely happy, of course if you're willing to hack it to support our formatting standards (ie, the double indent) then go right ahead.  Although again, I'm not sure it's worth the time... I'm happy just to 'fix' things up as we re-encounter them.
Glest Advanced Engine - Code Monkey

Timeline | Downloads

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Project Conventions
« Reply #12 on: 30 September 2009, 00:31:11 »
I agree with everything Silnarm writes. I wouldn't mind having no indenting with the switch but VC++ indents it anyway.

This program might make it a bit easier to configure the beautifiers.
http://universalindent.sourceforge.net/

Also I think if it's not a doxygen comment it should be a single line type comment so code can be easily commented out with multiline comments.

EDIT: Just read that using characters like $ in identifier names is non-portable.

EDIT2: Stroustrup recons use 0 rather than NULL and minimize use of plain reference arguments.
« Last Edit: 2 October 2009, 04:52:20 by hailstone »
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

daniel.santos

  • Guest
Re: Project Conventions
« Reply #13 on: 2 October 2009, 15:24:48 »
I'm not certain how I feel about always defining the values, I need sit on that one for a bit and see how I feel about it.  What are the advantages of always defining them as either 1 or 0 and the disadvantages of ifdef?  One thing I can say about advantages, is that it allows you to use actual C/C++ code (as opposed to C pre-processor code) and allow the compiler to do the work for you (as opposed to the pre-processor):

if(DEBUG_NETWORK) {
    // do some stuff.
}

For the debug build, it would include all of the code in the block in the object file and subsequent executable.  But when optimised (even mildly) it would completely eliminate it, just as if you had use #if DEBUG_NETWORK or #if DEBUG_NETWORK == 1.  A lot of people feel uncomfortable with this mixing of concepts, but it does indeed work quite nicely and allow you to do a lot of things you can't do just in the pre-processor language.

I agree with everything Silnarm writes. I wouldn't mind having no indenting with the switch but VC++ indents it anyway.
Sweet, then indented it is :)

This program might make it a bit easier to configure the beautifiers.
http://universalindent.sourceforge.net/
I don't really care about how easy or hard it is to configure, as much as how effective it is.  But I'll definitely take a look at it.  I would most certainly like to be aware of what all is out there (in the open source arena, not interested in closed-source).

Also I think if it's not a doxygen comment it should be a single line type comment so code can be easily commented out with multiline comments.
Having done a lot of C (strict ISO C) where you can't use C++ style:
// comments.
I've since adopted the habit of using
#if 0
#endif
to comment out large blocks of code.

I don't think we're using $ for any identifiers are we?  Also, I'll continue to use NULL because I think it makes your intention more clear: I mean a "pointer to no object" and not the numerical value zero.  The Java language went so far as to make "null" an actual keyword, and not just a pre-defined constant that translates into "0" or "(void*)0".

EDIT: One more note on the Javadoc-style Doxygen issue, just search the sources for the /** sequence of characters.  Currently, there are 250 instances.  I'm most certainly not going to change 250 instances of this without a very good reason! :)
« Last Edit: 2 October 2009, 20:35:34 by daniel.santos »

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Project Conventions
« Reply #14 on: 3 October 2009, 06:43:24 »
Quote
What are the advantages of always defining them as either 1 or 0 and the disadvantages of ifdef?
I was thinking of the documentation benefits. With all the constants visible where they are manipulated we don't need to look somewhere else. But then there might be a huge list.
« Last Edit: 3 October 2009, 06:47:04 by hailstone »
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Project Conventions
« Reply #15 on: 4 October 2009, 10:09:20 »
Sorry Guys, was away at a wedding this weekend, "out bush".

I think Hailstone has covered it, I'd just like to have all the possible debugging defines in one place.  It has the advantage that you only need to get it right once too, so for maintenance it is somewhat better too.
Of course, it does mean we'll have to be careful not to #ifdef by accident, but I think we'll get used to that pretty quickly.
Glest Advanced Engine - Code Monkey

Timeline | Downloads

daniel.santos

  • Guest
Re: Project Conventions
« Reply #16 on: 5 October 2009, 04:26:52 »
Yea, and we can have one header file with this in it:

Code: [Select]
#ifndef DEBUG_NETWORK
#   define DEBUG_NETWORK 0
#endif

// etc...

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Project Conventions
« Reply #17 on: 9 October 2009, 02:12:25 »
Addendum for #9

Internal documentation

Apparently our policy here is to prefer documentation in the module files, not headers (where possible).  Fine by me, shall we codify this one too?
Glest Advanced Engine - Code Monkey

Timeline | Downloads

daniel.santos

  • Guest
Re: Project Conventions
« Reply #18 on: 10 October 2009, 03:46:24 »
Hmm, very good good point/question/proposal/thought/ponderance.  I dunno, I sorta started the habit (good or bad) of documenting data members in the header, to the right like this:

Code: [Select]
class HelloWorld {
private:
    int goodbye;          /**< Some very short documentation. */
    string cruel;         /**< Some very, very long documentation that goes beyond the 100th column without a line break.  I don't know if I'm being lazy or if I'm trying to keep all of my data members together in one pretty place without line breaks so that its easier to read the actual code, figuring that we usually only care about these comments in the generated documentation. */
    bool world;           /**< Some other documentation. */
// etc...
};

But I think it maybe does make sense to document the functions in the .cpp file, but how should we document functions that are inlined in the class declaration?  I don't mean getters & setters, unless they have something special that needs to be documented, I would rather just document the data members themselves and leave getters & setters alone.  If we want to keep the class declarations as junked-free as possible, we can put documentation in the .cpp file like this:
Code: [Select]
/**
 * @fn void MyClass::myFunction(void *, int, const string &)
 * Documentation....
 */
// or...
/**
 * @fn void MyClass::myFunction(void * param1, int param2, const string &param3)
 * Documentation....
 */

The only crappy part about this is that if we change the signature to the function, or the name, the documentation has to be updated to match, whereas if we just put the documentation before the inline function declaration (and definition) in the class declaration, you don't have to worry about those details.

What's you guys' thoughts?

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Project Conventions
« Reply #19 on: 10 October 2009, 03:59:28 »
But I think it maybe does make sense to document the functions in the .cpp file, but how should we document functions that are inlined in the class declaration?  I don't mean getters & setters, unless they have something special that needs to be documented, I would rather just document the data members themselves and leave getters & setters alone.  If we want to keep the class declarations as junked-free as possible, we can put documentation in the .cpp file like this:

...

What's you guys' thoughts?


Yeah, I like the idea of keeping the headers clean if possible, but that's obviously not going to be possible all the time. I say just document what inline or templated functions require it in the headers, I don't think the extra maintenance is worth keeping it elsewhere.
Glest Advanced Engine - Code Monkey

Timeline | Downloads

daniel.santos

  • Guest
Re: Project Conventions
« Reply #20 on: 10 October 2009, 07:51:04 »
Ok, so maybe we can do the same thing with the super-long same-line comments for inline functions that are one-liners, but just use the standard method for anything non-trivial?  Example:

Code: [Select]
class MyClass {
//.....
    void pickNose() const     {nose += pick * finger + 1;}    /**< Some very bizarre function... */

    /** Some very icky function. */
    bool blowNose() const {
        Nose &nose = const_cast<Nose &>(Nose::getConstInstance());
        Boogers *boogers = nose.blow();
        return boogers ? boogers->isIcky() : false;
    }
}

Not that I want to be strict about it or go overboard, but just find some guidelines that will help keep the headers as booger-free as possible, while we add documentation.

Anyway, I'm off to bed.  I'll be back home Sunday and will actually be able to use IRC again (my gf's internet connection keeps dropping my IRC sessions  :'( )

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Project Conventions
« Reply #21 on: 10 June 2010, 04:16:38 »
I was experimenting in my assignments and found that prepending m_ for instance variables was quite useful to quickly bring them up in code completion. Also to a lesser extent prepending b for bools and ptr for pointers. I wouldn't want to go the full Hungarian style but b is used frequently in Unreal Script.

Eg:
m_bWalking is easy to see it's not a local variable or a parameter and is of bool type.

It's really nice to be able to glance at a piece of code and see exactly what instance variables are being used and modified.
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

jda

  • Guest
Re: Project Conventions
« Reply #22 on: 10 June 2010, 10:17:57 »
Is this ready to be stickied or is it still just in argueing discussing phase?
Not being a programmer myself, I still do understand the importance of conventions and readability... :D
I think a list of in-use coding conventions would be useful specially to programmers new to the project - this came to my mind after reading John.d.h's topic on "Gathering volunteers".

<Kinda OT> Also, some of the stickies, e.g. the "Todo list and bugs" thread, seem to be rather outdated / deprecated (for the example given, it's kinda deprecated to posting in the current release thread and the sourceforge.net Trac tickets are the best place for confirmed engine issues and sensible improvements). Maybe some reordering of the stickies would be fit?... </ Kinda OT>

As to hailstone's suggestion, I still do remember how useful that would've been in my old programming days...  :thumbup:

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Project Conventions
« Reply #23 on: 10 June 2010, 12:48:08 »
My understanding is this is a place for discussion. The official coding conventions were nicely collated by zombiepirate at https://sourceforge.net/apps/trac/glestae/wiki/CodingConventions see https://sourceforge.net/apps/trac/glestae/ticket/65

Also as a side note: Members are initialized in the order they were declared in the class definition not the order they appear in the member initalization list so it might be good to keep the same ordering to avoid confusion.
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

Yggdrasil

  • Local Moderator
  • Ornithopter
  • ********
  • Posts: 408
    • View Profile
Re: Project Conventions
« Reply #24 on: 10 June 2010, 21:50:56 »
Also as a side note: Members are initialized in the order they were declared in the class definition not the order they appear in the member initalization list so it might be good to keep the same ordering to avoid confusion.
GCC throws warnings about this. I'm fixing them every now and then.

I have no problem with prefixes like m_* which is quite common (i mostly use this->) but i actually dislike to encode the type in the name in some way. Look up the declaration or use a proper editor.