Sign in to follow this  

Coding Guidelines

Recommended Posts

After a feeled million hours of coding in the past 16 years there have been many ways to write code in many different languages. Some seemed correct to the time they were used, some seemed to be too strict or too chaotic and I also evolved my coding style with each new line written. Now considering the results of over 5 years in professionall game development, tools and engine code as hobbyist and on small and large commercial projects up to AAA titles, there are still many ways one could write code in different languages but also in the same language on different projects in one and the same but also different companies. I mostly agree with; see some trends in C#, C++ coding guidelines that are fully worth to go for but the major difference is on the naming conventions.

Because I have currently to write my own coding guidelines (not for a special project but primary as a personal convention to refer to when coding) and seek for a way I'm happy with, I did some research on different guidelines and came up with following references:

When Epic Games write about Unreal

Quote

Naming Conventions

  • The first letter of each word in a name (e.g. type or variable) is capitalized, and there is usually no underscore between words. For example, Health and UPrimitiveComponent, but not lastMouseCoordinates or delta_coordinates.

  • Type names are prefixed with an additional upper-case letter to distinguish them from variable names. For example, FSkin is a type name, and Skin is an instance of a FSkin.

    • Template classes are prefixed by T.

    • Classes that inherit from UObject are prefixed by U.

    • Classes that inherit from AActor are prefixed by A.

    • Classes that inherit from SWidget are prefixed by S.

    • Classes that are abstract interfaces are prefixed by I.

    • Enums are prefixed by E.

    • Boolean variables must be prefixed by b (e.g. "bPendingDestruction", or "bHasFadedIn").

    • Most other classes are prefixed by F, though some subsystems use other letters.

    • Typedefs should be prefixed by whatever is appropriate for that type: F if it's a typedef of a struct, U if it's a typedef of a UObject etc.

      • A typedef of a particular template instantiation is no longer a template and should be prefixed accordingly, e.g.:

        
        typedef TArray<FMyType> FArrayOfMyTypes;

This seems a bit confusing when seeking for some type like Animation or Skin (that are both different prefixed with A and F) but prevents various naming conflicts to types and variables when writing a function that accepts FSkin Skin as parameter for example.

Googles c++ guidelines point into a completely different direction when they write

Quote

Type Names

Type names start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum.

The names of all types — classes, structs, type aliases, enums, and type template parameters — have the same naming convention. Type names should start with a capital letter and have a capital letter for each new word. No underscores. For example:


// classes and structs
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

// typedefs
typedef hash_map<UrlTableProperties *, string> PropertiesMap;

// using aliases
using PropertiesMap = hash_map<UrlTableProperties *, string>;

// enums
enum UrlTableErrors { ...

Variable Names

The names of variables (including function parameters) and data members are all lowercase, with underscores between words. Data members of classes (but not structs) additionally have trailing underscores. For instance: a_local_variable, a_struct_data_member, a_class_data_member_.

Common Variable names

For example:


string table_name;  // OK - uses underscore.
string tablename;   // OK - all lowercase.

string tableName;   // Bad - mixed case.

Class Data Members

Data members of classes, both static and non-static, are named like ordinary nonmember variables, but with a trailing underscore.


class TableInfo {
  ...
 private:
  string table_name_;  // OK - underscore at end.
  string tablename_;   // OK.
  static Pool<TableInfo>* pool_;  // OK.
};

Struct Data Members

Data members of structs, both static and non-static, are named like ordinary nonmember variables. They do not have the trailing underscores that data members in classes have.


struct UrlTableProperties {
  string name;
  int num_entries;
  static Pool<UrlTableProperties>* pool;
};

See Structs vs. Classes for a discussion of when to use a struct versus a class.

Constant Names

Variables declared constexpr or const, and whose value is fixed for the duration of the program, are named with a leading "k" followed by mixed case. For example:


const int kDaysInAWeek = 7;

All such variables with static storage duration (i.e. statics and globals, see Storage Duration for details) should be named this way. This convention is optional for variables of other storage classes, e.g. automatic variables, otherwise the usual variable naming rules apply.

 

Function Names

Regular functions have mixed case; accessors and mutators may be named like variables.

Ordinarily, functions should start with a capital letter and have a capital letter for each new word (a.k.a. "Camel Case" or "Pascal case"). Such names should not have underscores. Prefer to capitalize acronyms as single words (i.e. StartRpc(), not StartRPC()).


AddTableEntry()
DeleteUrl()
OpenFileOrDie()

(The same naming rule applies to class- and namespace-scope constants that are exposed as part of an API and that are intended to look like functions, because the fact that they're objects rather than functions is an unimportant implementation detail.)

Accessors and mutators (get and set functions) may be named like variables. These often correspond to actual member variables, but this is not required. For example, int count() and void set_count(int count).

Namespace Names

Namespace names are all lower-case. Top-level namespace names are based on the project name . Avoid collisions between nested namespaces and well-known top-level namespaces.

The name of a top-level namespace should usually be the name of the project or team whose code is contained in that namespace. The code in that namespace should usually be in a directory whose basename matches the namespace name (or subdirectories thereof).

Keep in mind that the rule against abbreviated names applies to namespaces just as much as variable names. Code inside the namespace seldom needs to mention the namespace name, so there's usually no particular need for abbreviation anyway.

Avoid nested namespaces that match well-known top-level namespaces. Collisions between namespace names can lead to surprising build breaks because of name lookup rules. In particular, do not create any nested std namespaces. Prefer unique project identifiers (websearch::index, websearch::index_util) over collision-prone names like websearch::util.

For internal namespaces, be wary of other code being added to the same internal namespace causing a collision (internal helpers within a team tend to be related and may lead to collisions). In such a situation, using the filename to make a unique internal name is helpful (websearch::index::frobber_internal for use in frobber.h)

Enumerator Names

Enumerators (for both scoped and unscoped enums) should be named either like constants or like macros: either kEnumName or ENUM_NAME.

Preferably, the individual enumerators should be named like constants. However, it is also acceptable to name them like macros. The enumeration name, UrlTableErrors (and AlternateUrlTableErrors), is a type, and therefore mixed case.


enum UrlTableErrors {
  kOK = 0,
  kErrorOutOfMemory,
  kErrorMalformedInput,
};
enum AlternateUrlTableErrors {
  OK = 0,
  OUT_OF_MEMORY = 1,
  MALFORMED_INPUT = 2,
};

Until January 2009, the style was to name enum values like macros. This caused problems with name collisions between enum values and macros. Hence, the change to prefer constant-style naming was put in place. New code should prefer constant-style naming if possible. However, there is no reason to change old code to use constant-style names, unless the old names are actually causing a compile-time problem.

Macro Names

You're not really going to define a macro, are you? If you do, they're like this: MY_MACRO_THAT_SCARES_SMALL_CHILDREN.

Please see the description of macros; in general macros should not be used. However, if they are absolutely needed, then they should be named with all capitals and underscores.


#define ROUND(x) ...
#define PI_ROUNDED 3.0

Exceptions to Naming Rules

If you are naming something that is analogous to an existing C or C++ entity then you can follow the existing naming convention scheme.

bigopen()
function name, follows form of open()
uint
typedef
bigpos
struct or class, follows form of pos
sparse_hash_map
STL-like entity; follows STL naming conventions
LONGLONG_MAX
a constant, as in INT_MAX

So they heavily make use of typos, underscores and also lower case prefixes to identify different kinds of member, static, nonstatic and function names and in the same breath except there rules for various special cases.

Some other examples from different projexts I was invovled to also use and do not use prefixing types or use underscores

class Class
{
    const <type> cConstant;
    const <type> Constant;
    const <type> __Constant;
  
    <type> _myClassMember;
    <type> _MyClassMember;
    <type> myClassmember;
    <type> mMyClassMember;
  
    <type> function(<type> parameter);
    <type> Function(<type> parameter);
    <type> Function(<type> aParameter);
}
class NAClass //avoid using namespaces, instead prefix anything with a 2 letter namespace like identifier
{
    ... 
}

Dont need to mention that Visual Studio will raise a Warning/Exception that a type is named as same as a function parameter when using a class

class Container
{
    private int size; //current size
    public Resize(int size) //will cause compiler telling that type matches a member type
    {
        //do resize here
    }
}

So in the end anyone does he or she thinks that it is worth to be done and so me do too. I would like to hear your opinions to why and what codings style do you prefer or are involved to in whatever way. What do you think makes a good standard especially for the most common point, Naming Convetions?

Will be corious to read your opinions

Share this post


Link to post
Share on other sites

In the end it all comes down to your preferences, since the compiler wont care at all.  But generally, I think the important things are that whatever you choose is consistent throughout the code and creates as little confusion or obfuscation as possible.  Other things like typing speed can also come into play, but again that can be a matter of preference especially with auto-complete and other built-in features that may or may not exist in your code editor of choice.

Personally I use camelcase, avoiding underscores whenever possible, using them only in special cases.  I start my classes and function with upper case letters, local variables with lower case, and member variables start with "m" followed by capital letter for variable name.  Macros are all caps separated by underscores.  For curly braces I use Allman style because it aligns the curly braces and makes them easier to match up when looking at code, as well as separates the block of code inside the braces from the code before it... which again makes it easier to read for me.  I have trouble telling what code does if it's all bunched up into a solid brick of text.

Share this post


Link to post
Share on other sites
16 minutes ago, 0r0d said:

since the compiler wont care at all

There are a few things one should avoid, though -- one of which is listed as one of the last examples in the original post.

Identifiers should not start with leading underscores, nor should they contain double underscores. These can run into issues with reserved names.

 

Other than that I agree that's it's just a preference thing. If you're working with someone else, come to an agreement. The fact that there exists so many and different guidelines is good evidence for there not being any One True Style™.

Share this post


Link to post
Share on other sites

I mostly agree with the C# Style 0r0d mentioned except that in my opinion the leading m/a/c prefix for class/argument/constant types could lead to faster recognition what a name is used for but I personally feel that it leads to more thinking about "was this a member, argument or temporary I used here" rather than writing for the initial intention.

For example I know i need the size stored in my class right now so I would in some kind of subconscious auto typing write "size" and go ahead in the knowing of this beeing the correct addressor I intendet. Using a prefix "m" for my class member "mSize" could (or potentially would most of the time in my case) lead to a less subconscious typing but a conscious active reminder about "do not forgett that it isnt size rather than mSize" that might lead to a break in code flow.

When I had C# first and learned C++ later, there were no such things like prefixing your member/argument/constant whatever variables in my years of school at all.

Share this post


Link to post
Share on other sites

Prefixing type is generally a terrible idea.

Scope decoration, OTOH, can be kinda useful. Using m or _ for member variables, for example, allows differentiation between parameters and members, and also intellisense will quickly list all your members for that class. Sure, you could explicitly type "this->", but that's overkill.

I'm also open to prefixing pointers with p, purely because it makes your life a tiny bit easy when you're coding (variable. vs pVariable->).

But basically, pick a standard with your team, agree on it (quickly) and stick to it.

 

Readability is key.

Share this post


Link to post
Share on other sites
3 hours ago, 0r0d said:

How so?

CBecause GProgramming VIs Aa NWork POf NLiterature.  PIt VMakes PIt AVery VDifficult PFor NHumans VATo VRead CAnd AThe NCompiler PDoesn't VCare.

CAlso, IWhat's PWith CAll AThe GCapitalization PIn ASo AMany NGuidelines?

Edited by Bregma

Share this post


Link to post
Share on other sites
5 hours ago, 0r0d said:

How so?

Basically what @Bregma said.

All it does is add noise. It also discourages refactoring (int iThing = GetAThing() now returns a float, now we have rename every variable).

The whole lpszThisIsAString was a mistake in the first place. Initially, "Hungarian" notation was meant to encode metadata in the variable name. For example, wndX vs scnX to denote a window coordinate versus a screen coordinate. The idea was that if you see

wndX = scnX // oops should be wndX = ScreenToWindow(scnX)

it would look immediately wrong. 

But even that is no longer that useful (you could make different ScreenCoord and WindowCoord types, for example).

 

 

Share this post


Link to post
Share on other sites
4 hours ago, Bregma said:

CBecause GProgramming VIs Aa NWork POf NLiterature.  PIt VMakes PIt AVery VDifficult PFor NHumans VATo VRead CAnd AThe NCompiler PDoesn't VCare.

CAlso, IWhat's PWith CAll AThe GCapitalization PIn ASo AMany NGuidelines?

Oh, you were talking about prefixes for the type of a variable... that wasnt clear to me when I originally read your post.

Yeah I agree it's not a thing I would do.

I thought you were talking about prefixes for things like classes or functions, as in instead of namespaces.

i.e.:

rendTexture vs rend::Texture

or

rendGetTexture() vs rend::GetTexture()

Edited by 0r0d

Share this post


Link to post
Share on other sites

But is using mMember, aArgument and so on not the same as prefixing stuff; where

mWndPos = aWndPos + cWndPos;
//do some stuff to mWndPos;

*pWndPos = mWndPos;

is as same confusing as whatever Bregman wrote?

I know that it would make life easier when using some kind of member type to variable separation but writing this-> seems to be pretty standard here

Share this post


Link to post
Share on other sites
12 hours ago, Shaarigan said:

But is using mMember, aArgument and so on not the same as prefixing stuff; where


mWndPos = aWndPos + cWndPos;
//do some stuff to mWndPos;

*pWndPos = mWndPos;

is as same confusing as whatever Bregman wrote?

I know that it would make life easier when using some kind of member type to variable separation but writing this-> seems to be pretty standard here

I've never really seen anyone use "a" as a prefix for an argument variable.  In any case, I find "m" a very valuable thing to differentiate from inputs and locals.  There are a couple others that I use, but in general if you get carried away with Hungarian notation it all becomes a horrible mess.

The prefixes that I DO use because I find them useful are "p" for pointer, "b" for bools, "k" for constants.  Maybe sometimes "s" for statics.

Prefixes like this are like anything else, they can be good in moderation, but it gets out of hand quickly if you're not careful.

Share this post


Link to post
Share on other sites
18 hours ago, 0r0d said:

The prefixes that I DO use because I find them useful are "p" for pointer, "b" for bools, "k" for constants.  Maybe sometimes "s" for statics.

While I also use "p" for pointer,  I used to do "b" for bools as well, but now I find it rather distracting. I instead tend to prefix my booleans based on the use-case. "isConst", "wasCalled", "hasAttribute" ... all make it pretty clear that its a boolean, and IMHO easier to read then "bConst", "bCalled", "bAttribute", especially in combination with member-variable prefab "m_bConst" vs "m_isConst".

 

Share this post


Link to post
Share on other sites
6 hours ago, Juliean said:

While I also use "p" for pointer,  I used to do "b" for bools as well, but now I find it rather distracting. I instead tend to prefix my booleans based on the use-case. "isConst", "wasCalled", "hasAttribute" ... all make it pretty clear that its a boolean, and IMHO easier to read then "bConst", "bCalled", "bAttribute", especially in combination with member-variable prefab "m_bConst" vs "m_isConst".

 

Yeah, that's a good way to do it.  I mostly use "b" because it's what I've done for a long time and I'm used to seeing it, and all the existing code is that way.  But generally I dont use type prefixes since like you point out, it gets really messy when you start combining them with other prefixes.  I do basically do that, however, for functions:

Instead of:

bool GetActive()

I just do:

bool IsActive()

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      628765
    • Total Posts
      2984582
  • Similar Content

    • By hiya83
      (Posted this in graphics forum too, which was perhaps the wrong forum for it)
      Hey, I was wondering if on mobile development (Android mainly but iOS as well if you know of it), if there is a GPUView equivalent for whole system debugging so we can figure out if the CPU/GPU are being pipelined efficiently, if there are bubbles, etc. Also slightly tangent question, but do mobile GPU's have a DMA engine exposed as a dedicated Transfer Queue for Vulkan?
      Thanks!
    • By pabloreda
       
      I am coding the rasterization of triangles by the baricentric coordinate method.
      Look a lot of code and tutorials that are on the web about the optimization of this algorithm.
      I found a way to optimize it that I did not see it anywhere.
      I Only code the painting of triangles without Zbuffer and without textures. I am not comparing speeds and I am not interested in doing them, I am simply reducing the amount of instructions that are executed in the internal loop.
      The idea is simple, someone must have done it before but he did not publish the code or maybe in hardware it is already that way too.
      It should be noted that for each horizontal line drawn, of the three segments, you only need to look at one when going from negative to positive to start drawing and you only need to look at one when it goes from positive to negative when you stop drawing.
      I try it and it works well, now I am implementing a regular version with texture and zbuffer to realize how to add it to this optimization.
      Does anyone know if this optimization is already done?
      The code is in https://github.com/phreda4/reda4/blob/master/r4/Dev/graficos/rasterize2.txt
      From line 92 to 155
       
    • By FFA702
      Hi. It's been a while since I posted here, and my last posts are almost about this exact same subject. Just saying to demonstrate how annoying this is to me.
      Here is the problem : I'm trying to make a decent raycaster in C#. The main issue is that for this to happen, I need pixel by pixel drawing. My previous raycaster used VS GDI+, and trough several tricks involving pointers and filling a bitmap byte by byte, I was able to obtain half decent results, and make an online server-client style 3d engine complete with a map builder and several really cool features. I unfortunately wasn't able to expand the project further due to poorly written code (I am an hobbyist, I study Business Administration at Uni) and the fact that my quick hack for performance was barely able to carry the bare minimum of what I needed to make a very bare bone raycaster possible. This came with very real sadness, the realization that the project I spent almost 2 years on was essentially useless, bloated and impossible to expand on. 
      Enough background. Now, starting anew, my main concern is to find a way to gain fast pixel by pixel control over the screen. I'm using SFML and C#. My current testbench is pretty simple, I'm using a method I found on the internet written for C++. I Adapted it for C#. I'm filling a Color[,] array (each color is a pixel) and then I copy the RGB values inside a byte[] array before moving them inside the texture buffer. I then display the texture on the screen. I'm not sure what the bottleneck is, the application is faster than my previous one, but it's still too slow for my liking. Raycasters work by redrawing stuff ontop of other stuff, and I fear that adding more stuff would creep it to an halt. I'm posting what I have as a testbench right now, any help would be greatly appreciated. Keep in mind I am not a professional programmer by any mean, I am pretty uncomfortable with pointers and true 3d stuff, but I will use them if I must. 
      using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using SFML.Audio; using SFML.Graphics; using SFML.System; using SFML.Window; namespace RayCastFF { class Program { public static int TestCounter = 0; public static Color[,] ScreenBuffer = new Color[640, 360]; //an array containing the color of all the pixel, this is intended to be the main target of all manipulation and draw call public static Texture MainViewPort = new Texture(640, 360);//main screen texture unsafe static void Main(string[] args) { //MAINWINDOW SETUP RenderWindow window = new RenderWindow(new VideoMode(640, 360), "RayCaster"); while (window.IsOpen)//MAIN GAME LOOP { //CALL FOR UPDATE Update(); //DRAW window.Clear(); window.DispatchEvents(); Sprite mainviewport = new Sprite(MainViewPort); window.Draw(mainviewport);//draw the texture over the screen window.Display(); //TAKE INPUT } } static void Update() { TestCounter++; if (TestCounter > 639) { TestCounter = 0; } //RESET THE BUFFER (COULD BE REMOVED LATER I GUESS) for (int x = 0; x < 640; x++) { for (int y = 0; y < 360; y++) { ScreenBuffer[x, y] = Color.Black; } } //DO STUFF DrawLine(Color.Red, TestCounter, 200, 100); //(for this test, i simply draw a moving line) //WRITING THE BUFFER INTO THE IMAGE //THIS SHOULD ALWAYS BE THE LAST STEP OF THE UPDATE METHOD byte[] pixels = new byte[640 * 360 * 4]; //640 x 360 pixels x 4 bytes per pixel Color[] cpixels = new Color[640 * 360];//intermediary step to keep everything clear for (int x = 0; x < 640; x++) { for (int y = 0; y < 360; y++) { cpixels[x+(640*y)] = ScreenBuffer[x, y];//make an intermediary array the correct dimention and arrange the pixels in the correct position to be drawn (separate step to keep everything clean, I find this operation incredibly confusing mainly because I had no idea how the pixels are supposed to be arrenged in the first place(still kind of dont)) } } for (int i = 0; i < 640 * 360 * 4; i += 4)//fill the byte array { pixels[i + 0] = cpixels[i / 4].R; pixels[i + 1] = cpixels[i / 4].G; pixels[i + 2] = cpixels[i / 4].B; pixels[i + 3] = cpixels[i / 4].A; } MainViewPort.Update(pixels);//update the texture with the array } //[X , Y] static void DrawLine(Color color, int Wpos, int Ytop, int Ybottom)//simple draw method making a vertical line { for (int y = Ybottom; y < Ytop; y++) { ScreenBuffer[Wpos, y] = color; } } } } What I'd like to end up with is a very fast way to draw the pixels on the window by the abstraction of a single 2d array of 640x360 unit that I could easily and simply manipulate. However, while being simple, it's also somewhat slow. It's also using 30% GPU load for some reason on a 1070GTX 8GB. Again, any help would be greatly appreciated.
      Thanks in advance.
    • By Tanzan
      Hello all,
      My question is a bit hard to describe but hopefully it will do...
      I just wonder what you guys think is the 'best' way of getting info about the model in your view(s)..
      To clearify (i hope ;-) )
      If the model is updating itself every game-cycle and the  (deep) nested objects all do there jobs how do you get info where only the view is interested in?
      So my question is not how to do it but more what do you people think is the best way to do it ?
       
      Regards,
       
      Alex   
    • By aejt
      Sorry for making a new thread about this, but I have a specific question which I couldn't find an answer to in any of the other threads I've looked at.
      I've been trying to get the method shown here to work several days now and I've run out of things to try.
      I've more or less resorted to using the barebones example shown there (with some very minor modifications as it wouldn't run otherwise), but I still can't get it to work. Either I have misunderstood something completely, or there's a mistake somewhere.
       
      My shader code looks like this:
      Vertex shader:
      #version 330 core //Vertex shader //Half the size of the near plane {tan(fovy/2.0) * aspect, tan(fovy/2.0) } uniform vec2 halfSizeNearPlane; layout (location = 0) in vec3 clipPos; //UV for the depth buffer/screen access. //(0,0) in bottom left corner (1, 1) in top right corner layout (location = 1) in vec2 texCoord; out vec3 eyeDirection; out vec2 uv; void main() { uv = texCoord; eyeDirection = vec3((2.0 * halfSizeNearPlane * texCoord) - halfSizeNearPlane , -1.0); gl_Position = vec4(clipPos.xy, 0, 1); } Fragment shader:
      #version 330 core //Fragment shader layout (location = 0) out vec3 fragColor; in vec3 eyeDirection; in vec2 uv; uniform mat4 persMatrix; uniform vec2 depthrange; uniform sampler2D depth; vec4 CalcEyeFromWindow(in float windowZ, in vec3 eyeDirection, in vec2 depthrange) { float ndcZ = (2.0 * windowZ - depthrange.x - depthrange.y) / (depthrange.y - depthrange.x); float eyeZ = persMatrix[3][2] / ((persMatrix[2][3] * ndcZ) - persMatrix[2][2]); return vec4(eyeDirection * eyeZ, 1); } void main() { vec4 eyeSpace = CalcEyeFromWindow(texture(depth, uv).x, eyeDirection, depthrange); fragColor = eyeSpace.rbg; } Where my camera settings are: float fov = glm::radians(60.0f); float aspect = 800.0f / 600.0f; And my uniforms equal: uniform mat4 persMatrix = glm::perspective(fov, aspect, 0.1f, 100.0f) uniform vec2 halfSizeNearPlane = glm::vec2(glm::tan(fov/2.0) * aspect, glm::tan(fov/2.0)) uniform vec2 depthrange = glm::vec2(0.0f, 1.0f) uniform sampler2D depth is a GL_DEPTH24_STENCIL8 texture which has depth values from an earlier pass (if I linearize it and set fragColor = vec3(linearizedZ), it shows up like it should, so nothing seems wrong there).
      I can confirm that it's wrong because it doesn't give me similar results to what saving position in the G-buffer or reconstructing using inverse matrices does.
      Is there something obvious I'm missing? To me the logic seems sound, and from the description on the Khronos wiki I can't see where I go wrong.
      Thanks!
  • Popular Now