From Emergent
Names
- Types and Methods are InitialUpper (CamelCase)
- members are all_lower_case w/ underbars
- property accessors can be initial lowerThenUpper (setName, getName etc) -- Qt convention; also Methods InitialUpper is in wide use already. kinda ambiguous
- ENUMS are all UPPER
- do try to include the full name, but if it is going to be combined with various other name elements, then abbreviations are good to prevent insanely long names. Projection -> Prjn is a good thing.
class Objects
- if possible, just use public members without accessor functions -- much simpler interface for user
- unless there is a specific good reason, just make everything virtual and not private, because you never know what kind of new usage people will think of. it is presmtive to think you can anticipate all reasonable uses of your code!
Template for a new class with members
class MY_API MyClass : public taNBase {
/* ##CAT_MyCat this comment is very important as it provides an overview of what
this class does for anyone who might use it -- it is builtin documentation
also, the #CAT_ directive is critical for allowing people to search for objects
according to semantically relevant categories */
INHERITED(taNBase) // this is ESSENTIAL: just the name of our parent class
public:
float my_member; // again, docs here are critical for users!!
float DoSomething(int arg1); // document me, including what each arg does!
TA_SIMPLE_BASEFUNS(MyClass); // this does all the housekeeping
protected:
void UpdateAfterEdit_impl(); // do any updates to members after user edits
private:
void Initialize() { my_member = 2.07f; } // this is the constructor, init all members
void Destroy() { CutLinks(); } // destructor -- call CutLinks and other stuff
};
Template for a new class without members
class MY_API MyClass : public taNBase {
/* ##CAT_MyCat this comment is very important as it provides an overview of what
this class does for anyone who might use it -- it is builtin documentation
also, the #CAT_ directive is critical for allowing people to search for objects
according to semantically relevant categories */
INHERITED(taNBase) // this is ESSENTIAL: just the name of our parent class
public:
float DoSomething(int arg1); // document me, including what each arg does!
TA_BASEFUNS_NOCOPY(MyClass); // NOCOPY required for no members (SIMPLE does auto-copy)
private:
void Initialize() { }; // nothing to do
void Destroy() { }; // destructor -- no CutLinks if no members
};
Exceptions to above cases (rarely needed)
- If there will be a large number of instances of an object (e.g., a Unit in a Network), then have the following basefuns code, which does a manual copy function instead of using the automatic but slower one provided by the TA_SIMPLE_BASEFUNS:
void Copy_(const MyClass& cp); // efficient manual copy function, not SIMPLE auto one
TA_BASEFUNS(MyClass); // note: no SIMPLE (does auto-everything) and no NOCOPY
- If such a class has members which are themselves taBase objects, these objects need to be owned in the InitLinks function, which must be written by hand for speed (again, TA_SIMPLE_BASEFUNS provides an automatic one, but it slower):
// in .h file, in public section just above void Copy_( function:
void InitLinks():
// in .cpp file:
void MyClass::InitLinks() {
inherited::InitLinks(); // inherited is always my parent
taBase::Own(my_ta_member, this); // owns the member (reference count, sets owner)
}
- The first Spec class for a given type of algorithm (e.g., BpConSpec, BpUnitSpec) requires special InitLinks code:
void BpConSpec::InitLinks() {
inherited::InitLinks();
children.SetBaseType(&TA_BpConSpec); // allow any of this basic type here
children.el_typ = GetTypeDef(); // but make the default to be me!
taBase::Own(lrate_sched, this); // don't forget to own any taBase members!
}
Flags
- at the first thought of adding a bool field to an object, add flags instead. where there is one, there are likely to be more.. flags are just so much more sensible..
- Avoid NO_xxx flags -- keep everything in the affirmative, and just go ahead and put the proper intialization stuff in the Initialize section. not so hard.
- use #BITS and #NO_BIT to provide direct gui access
- Example std function names for manipulating flags:
inline void SetColFlag(ColFlags flg) { col_flags = (ColFlags)(col_flags | flg); }
// set data column flag state on
inline void ClearColFlag(ColFlags flg) { col_flags = (ColFlags)(col_flags & ~flg); }
// clear data column flag state (set off)
inline bool HasColFlag(ColFlags flg) const { return (col_flags & flg); }
// check if data column flag is set
inline void SetColFlagState(ColFlags flg, bool on)
{ if(on) SetColFlag(flg); else ClearColFlag(flg); }
// set data column flag state according to on bool (if true, set flag, if false, clear it)
Program Coding
- Always use ProgVarRef's instead of direct references to objects of a particular type (e.g., DataTableRef) -- using an intermediate program variable makes things much more flexible, and they often exist anyway.
- Always use ProgExpr for any kind of expression that the user can type in themselves - auto updates when variables change, and provides a lookup feature, etc.