JavaScript:SpiderMonkey:C++ Coding Style

From MozillaWiki
Revision as of 08:49, 7 April 2010 by Cdleary (talk | contribs) (Added initializer list style.)
Jump to navigation Jump to search

Basics

The C Coding Style Guidelines apply unless overridden here. If this becomes awkward we should fork and diverge instead of referencing.

The rest of this page is a strawman proposal. Feel free to add, amend, or even correct if something is obviously wrong. Raise issues in the newsgroup.

C++ is powerful, with many degrees of freedom and some attractive nuisances. We should aspire to use it in a lean, close-to-the-metal fashion, and avoid style-over-substance bikeshedding.

Namespaces

  • Instead of JS/js and JS_ prefixing for public function and type names, respectively, use
namespace JS { ... }
  • Instead of js_ prefixing for library-private and "friend" functions,
namespace js { ... }
  • Compile-time-evaluated functions (i.e., template meta-functions) are kept in the "template library" namespace to avoid collision with their runtime counterparts.
namespace js { namespace tl { ... } }
  • Other namespaces? Are these names too short and likely to collide?

Classical OOP

  • Most structs can become classes, with associated functions becoming methods. This already started for the upvar2 bug.
    • Style detailing: mrbkap suggests left brace before class body on its own line in column 1 to match function style and facilitate vim navigation. People do this already when inheriting, since the left brace can get lost in the superclass(es).
class JSObject
{
     ...
}
  • Member variable names, private or public, are not decorated. Examples of improper decoration include:
class Fail
{
  size_t capacity_;  // unsightly
  T *mBegin;         // makes babies cry
  T *m_end;          // much typing
}

Sometimes a canonical argument name may conflict with a member name. In this case, one can disambiguate with "this->", although such explicit qualification should only be added when necessary:

class C
{
  size_t count;
  bool fresh;
  void change(size_t count) {
    this->count = count;
    this->fresh = false;  // verbose and unnecessary
  }
};
  • Most macros become inline helpers. With LiveConnect gone on mozilla-central, we can make the helpers methods of relevant structs or classes finally, instead of static inline functions.
  • Based on 20+ years of bad experiences, we are going to go slow and resist virtual methods and bases, MI, and the like. Function pointer tables for now, as before -- see JSObjectOps needs a make-over.
  • Templates are good, Mozilla has positive experience and the portability is there for the kind of RAII helpers we need.
  • No exceptions, so std is hard to use. There is initial work underway to make STL-like containers that mesh well with the rest of the JS engine (see js::Vector, js::HashMap, js::Pool).
    • There are still improvements to be made to the new hash table: double-hash implementation; improve bit-mixing into multiplicative hash if the cycle costs can be supported (measurement is required and we should understand down to the bits what is going on); a js::HashSet or js::HashMap<T,void> specialization such that set-like use of hashtables do not waste any space on values.
  • Initializer lists can break in one of two ways. The first may be preferable when constructors take few arguments:
class Ninja : public WeaponWeilder, public Camouflagible,
              public Assassinatable, public ShapeShiftable
{
    Ninja() : WeaponWeilder(Weapons.SHURIKEN),
              Camouflagible(Garments.SHINOBI_SHOZOKU),
              Assassinatable(AssassinationDifficulty.HIGHLY_DIFFICULT),
              ShapeShiftable(MPCost(512)) {}
}

The other permitted style mitigates longer-identifiers-squishing-text-against-the-right-side-of-the-screen-syndrome by using a half-indented colon:

class Ninja
  : public WeaponWeilder, public Camouflagible, public Assassinatable,
    public ShapeShiftable
{
    Ninja()
      : WeaponWeilder(Weapons.SHURIKEN),
        Camouflagible(Garments.SHINOBI_SHOZOKU),
        Assassinatable(AssassinationDifficulty.HIGHLY_DIFFICULT),
        ShapeShiftable(MPCost(512)) {}
}

Boolean Types

  • We would like to use the C++ 'bool' type wherever possible, but we must avoid breaking public and 'friend' APIs that use JSBool. So public header files (and semi-public headers, like 'jsopcodes.h') should continue to use 'JSBool', 'JS_TRUE', and 'JS_FALSE'. In all SpiderMonkey '.cpp' files, use 'true' and 'false', never 'JS_TRUE' or 'JS_FALSE'. Use 'bool' whenever doing so would not conflict with a declaration in a public or semi-public header.

References