Naming convention fit for C++

Discussion in 'C++' started by Carl Colijn, Nov 18, 2005.

  1. Carl Colijn

    Carl Colijn Guest

    Hi all,

    Disclaimer: before I might trigger your "let's start a holy war!" button,
    I'd like to say I'm not intended to; I just post this message to get some
    input and not to promote "Yet Another Naming Convention". It's a bit of a
    long post, but I've spent the past few days on perfecting this, finally came
    to the conclusion that maybe I went a bit overboard with it, almost willing
    to just say "the @#$ with it" but I didn't want to let it all go to waste...
    Anyway, here it goes:

    Up till now, I used a naming convention I borrowed from my last 2 jobs (I
    switched jobs together with the team manager). Since I didn't have any
    convention before that, I just adopted it and thought nothing about it ever
    since, and I also used it for hobby projects at home. It's a form of
    shortened and generalized Hungarian Notation, applied the wrong way as well;
    "explicit data type = prefix" in stead of "intended data type = prefix". To
    give an idea: all numbers have a prefix 'n' (from number), all class
    instances an 'o' (from object), possibly resulting in e.g. compiling but not
    wrong-looking "nDayOfTheWeek = nCircleRadius" or "nColor =
    oBankAccount.GetID()" (where GetID returns e.g. an int or so).

    But now the times have changed, and I've started making serious programs for
    my own company (hurray!). And then a shortcoming in my inherited coding
    convention started biting me in the @ss (two distinct usage of the same data
    type getting mixed up, causing an infrequent bug that almost slipped my
    attention); time to rethink the coding convention.

    I read some (well, a lot of) posts, trying to extract some usefull ideas
    from out of the usual bickering about coding conventions. What I've come up
    with so far is a syntax that has aspects of "True" Hungarian notation and
    common SmallTalk conventions (or so I've heard). I think the benefit of it
    is that code inspection will catch some bugs compilers won't catch (like in
    True Hungarian; one basic type being used for more than one variable, all
    with another purpose, and mixing the purposes up). Furthermore it's much
    more closer to standard English than Hungarian is, so the names (kind of)
    read out like you'd call the thing in plain English. And the downside of
    Hungarian (getting to remember all those zillion standard abbreviations, and
    then also invent and maintain your own) is also bypassed.

    ============== Syntax ==============

    0) Scope prefixes
    m: member scope
    g: global scope

    1) Modifier prefixes
    c: const
    h: handle to
    p: pointer to
    r: reference to
    s: set of

    2) Typenames
    T[<modifiers>]<Type>;
    So, typenames can have modifiers embedded into them if needed for
    clarification.

    3) Subject (helper intermediate stage for Variables and Functions)
    [<modifiers>][<Name>]<Type>
    Any modifiers embedded in the used type will migrate to the front with the
    rest of the modifiers (but keep their relative order).
    I'm still not sure whether the <Name> part should be optional...

    4) Variables
    [<scope>]<Subject>

    5) Functions
    <Name(Action)>_<Subject(ReturnType)>[_<Name(Clause1)>_<Subject(Clause1)>[_<Name(Clause2)>_<Subject(Clause2)>[...]]]
    The optional clauses denote extra info on the workings of the function in
    terms of the parameters; clause 1 descibes parameter 1, etc. Not all
    parameters need to be described (I want to keep overloading to work), but
    immutable _intended_ parameter usage will benefit from this I think.

    6) 'Procedures' (void functions)
    <Name(Action)>[<Name(Clause1)>_<Subject(Clause1)>[_<Name(Clause2)>_<Subject(Clause2)>[...]]]

    7) Additional rules
    Type will be the name of the intended type used, not the exact
    implementation.
    Abbreviation of names and types is allowed, unless it diminishes the
    clarity.

    Ok, now that the rules are laid out, lets show some examples of what this
    boils down to:

    ============== Examples ==============
    // Date class that manipulates dates, and is compatible with the type
    'double'
    class TDate {
    ...
    };

    // Set of pointers to dates
    typedef std::vector<TDate*> TspDate;

    // Date variable
    TDate* pStartDate;
    double EndDate;

    // Member instance of the set of pointers to date;
    // keeps a set of references to start dates.
    class ... {
    TspDate mspStartDate;
    TColor mColor; // No explicitly added name; can only have 1 color
    };

    // Function returning a date
    // Declaration:
    TDate* Get_pDate_From_crDataFile(const TDataFile& crInputDataFile, TDate
    DefaultStartDate);
    // Usage:
    double UnknownDate = 0.0;
    *ppStartDate = Get_pDate_From_crDataFile(TempDataFile, UnknownDate);

    // Function performing some action
    // The 2nd parameter can be said to be of type "format"
    // Declaration:
    Print_Date(double Date, char* DisplayFormat);
    // Usage:
    Print_Date(mStartDate, "ddmmyyyy");


    Ok, these examples are good to understand for everyone I think (well, I
    hope). The downside I think is that the notation is _quite_ verbose, but
    any misinterpretation is minimalized.

    Another downside is that the verbosity can quickly add up when you have
    extended types via typedefs; a live example from the code I used to test the
    convention:
    class ... {
    private:
    typedef std::map<TStatCacheID, TStatInt*> TspStatCacheID2StatInt;
    TspStatCacheID2StatInt mspStatCacheID2StatInt;
    }
    where before I would have used:
    typedef std::map<CStatCacheID, CStatInt*> CID2Int;
    CID2Int m_apIntsByID;
    In this case the extra abbreviation of the class type isn't harmfull,
    because all classes involved have no conversion operators whatsoever (all
    misuse will be penalized with a compile error). Using the new convention
    doubles the names, which makes code lines scroll off the screen quite
    fast... And though I strive for perfection of my code, I'm also lazy enough
    not to want to type "mspStatCacheID2StatInt" every time...

    Yet another thing I find at fault with this convention is that, althoug the
    name is suffixed with the type, there is no delimiter between them (DataFile
    InputDataFile; is that a File for InputData, or a DataFile for Input?). The
    underscore is already reserved for use in functions (where I need to
    seperate the actions from the subjects), and CamelCase is already at work
    within the names and types. If only I could use bold or italics in my code
    :(

    And a final grudge I have about this new convention is that flag values
    (booleans) have no clear type; what about e.g.:
    bool Get_Success_FromPrint_pDate(TDate* pDate);
    I'd rather just use Print_pDate(...) ... Or:
    bool FailSuccess = !Get_Success_From....()
    type returned by the function is "Success", so the variable better have that
    type as well (don't want to loosen the usage of the convention; if I allow
    so, then what's the use?). I could use a general flag type called "Flag"
    (typedef bool TFlag), but that makes the looks-like-English to fail;
    TFlag SuccessFlag = Get_Flag_From...()
    or
    TFlag SuccessFlag = Get_SuccessFlag_From...()
    which is even more verbose...

    In my code I make use of two types of dates; dates in local time and dates
    in UTC. Obviously it's not a good idea to mix these without using mapping
    functions ("ToLocal()", "ToUTC()"). In my old notation, both types would
    cause a prefix letter 'd' (from 'date') to be used, but now I just 'invent'
    the type TDateL and TDateU (both typedefs to a class TDate from a library I
    use). This still won't cause the compiler to catch any semantic errors, but
    any code review will.

    I did try a better solution: generating 2 derived classes from TDate. But
    that caused a lot of headaches as well; I either have to recreate all
    constructors and assignment operators (and TDate has a lot of those :) );
    this task I can alleviate by adding a templatized constructor like
    template<typename TParam>
    TDateU(const TParam& crParam): TDate(crParam) {};
    but that still leaves implicit conversions like e.g.
    TDateU => double => TDateL, or
    TDateU => SYSTEMTIME => TDateL
    and I _need_ those conversions (I do a lot of arithmetic with and
    conversions of dates).

    And so the bottom line: what do you think of it? Any ideas about the
    verbosity?

    Thanks for reading this far ;)
    Kind regards,
    Carl
    Carl Colijn, Nov 18, 2005
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rick

    Which c# naming convention?

    Rick, Jan 19, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    3,773
    Paul Glavich
    Jan 19, 2004
  2. dm1608
    Replies:
    6
    Views:
    8,511
  3. Buck Turgidson

    JSP Method Naming Convention

    Buck Turgidson, Mar 2, 2004, in forum: Java
    Replies:
    1
    Views:
    1,748
    P.Hill
    Mar 2, 2004
  4. harry
    Replies:
    2
    Views:
    1,187
    harry
    Dec 8, 2004
  5. Piet
    Replies:
    0
    Views:
    518
Loading...

Share This Page