// Copyright (c) 2007 Art & Logic, Inc. All Rights Reserved. // $Id: $ // Above: [sf02], [sf03] // a note on the stuff inside the square brackets: // Each of the codes inside brackets is a reference to the rule(s) in the // Style Guide that's being illustrated, as follows: // [sf##] - StyleGuide/SourceFiles // [cas##] - StyleGuide/ClassesAndStructures // [nr##] - StyleGuide/NamingRules // [cg##] - StyleGuide/Commenting // [fmt##] - StyleGuide/Formatting // Throughout: [fmt01]; all indentation done with space characters (0x20), // three spaces per logical tab stop. // [nr21] C/C++ guard to prevent recursive inclusion of header files // !!! Javascript - no preprocessor syntax !!! // [sf05] // !!! Javascript - no specific include syntax !!! // [nr25] the 'q' prefix indicates that we are controlling conditional // !!! Javascript - no precompilation macros !!! // [sf07], only one class declared/defined in this source file. // [cg02], comments useful to programmers who will use (but not necessarily // maintain) this class are separated out into the header file, not in the // implementation file. /** * ARosetta * Simple, but meaningless class to demonstrate Art+Logic programming * style conventions as they are applied to the various programming languages * we use. In several places, you're asked to imagine a block of useful code * to avoid distracting you from the issues of formatting (etc) that are being * demonstrated. * * As you've already seen above, the thing about to be shown in this file is * called out in comments using the A+L-style markup '!!!' */ // [nr11], [nr18] class names prefixed with "A" // !!! Javascript - Objects are declared using the Constructor function syntax !!! // [cas01] public member functions/methods listed first // !!! Javascript - Should be listed after Constructor function for clarity !!! // [nr08] new non-class types (enumerations, data structures, etc) are // named with MixedCase and no special prefix // !!! Javascript - No such syntax beyond functions !!! /** * Construct and initialize the Rosetta object. * \param fileName The file to use as our data source */ function ARosetta(fileName) { // [cas01] Protected member functions declared after public // !!! Javascript - Privileged functions are declared in JS using // 'this' keyword to assign function to member !!! // protected: /** * [nr03] parameters passed to functions are named using lowerCamelCase */ this.Test = function(firstVal, secondVal) { var retval = true; // [fmt07] -- if/else formatting if (firstVal < secondVal) { // [cg06] -- use '$$$' as a marker to indicate a request that the // following block of code be reviewed before a change is considered // complete // $$$ before // this->Process(secondVal); // $$$ after // Shouldn't this be processing the first value in this case? this.Process(firstVal); // $$$ end } else if (secondVal > kSomeConstant) { this.Process(secondVal); } else { // [fmt18] -- use curly braces even in cases where the language doesn't // require it to prevent maintenance errors. retval = false; } } // [cas01] Private member function declared after protected // !!! Javascript - Private members functions are private to the constructor function through Closures !!! // private: /** * Useful function to process something or other. */ function Process(val) { // [cg05] -- use '!!!' as a marker to indicate a section of code that // requires attention // !!!... removing old hardcoded value // fProcessResult = 131; // ...!!! var result = val; while (--val) { result *= val; } fProcessResult = result; } /** * Demonstrating the formatting of a switch statement. */ function Decide(midiEventType) { // [fmt11] -- switch/case formatting. switch (midiEventType) { // comments precede the case case kNoteOn: this.NoteOn(now); if (duration > 0) { this.NoteOff(now + duration); } break; case kNoteOff: this.NoteOff(now); break; case kPolyAfter: after = channelValue; // [fmt35] include, but comment out the break when falling through intentionally. // break; case kChannelAfter: this.AfterTouch(after); break; // [fmt36] no need to include a commented out break when falling through an empty case case kPitchbend: // blank line... // [fmt12] -- switch statements should always have a default case. default: ASSERT(false); this.LogError("Unsupported event type!"); break; } } // [cas02] member variables declared in the same order: public // (avoid in most languages), protected, private. // !!! Javascript - Public member variables must be declared OUTSIDE of constructor function !!! // protected: // !!! Javascript - Use this keyword with identifier to declare variable !!! // private: // [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed // by an uppercase letter. // [fmt28] -- when declaring pointer variables, attach the '*' to the // typename, not the variable name. // !!! Javascript - no pointer syntax !!! var fInputFile = new (fFilename); // !!! Javascript - To declare a member variable, you should always assign a value or null !!! var fProcessResult = 0; } // !!! Javascript - Public methods associated with the ARosetta object prototype !!! // /** * [nr07] Member functions are named using CamelCase, with a leading upper case * letter. */ ARosetta.prototype.MemberFunctionWithMultipleWords = function() { var ok = true; // [fmt08] -- formatting of a for() loop. for (var i = 0; i < kSomeConstant; ++i) { for (var j = 0; j < kSomeOtherConstant; ++j) { // [fmt02] -- preprocessor directives go in column zero. // !!! Javascript - No preprocessor syntax !!! // [nr07] -- Calls to member functions of the current object are // made through an explicit this-> pointer. // !!! Javascript - no pointer syntax, everything is by reference e.g this.member ok = this.Test(i, j); if (!ok) { alert("Fatal error testing: " + i + ", " + j ); // goto CleanUp; // !!! Javascript - no labels, use break !!! break; } } } // [fmt19] if (ok) { return true; } else { return false; } // [fmt02] -- labels used as the target of a goto are placed in column zero. // CleanUp: // cleanup code here... // !!! Javascript - no labels } /** * !!! Here's how we handle very long lines (i.e., longer than 79 * characters) */ ARosetta.prototype.LongLineWrapping = function() { // [fmt03] -- source lines should be less than 80 characters long. // [fmt04] -- break lines at the most logical point // 1 2 3 4 5 6 7 //34567890123456789012345678901234567890123456789012345678901234567890123456789 var retval = FunctionWithManyArguments(longArgumentName1, longArgumentName2, longArgumentName3, longArgumentName4); // alternative format #1 retval = FunctionWithManyArguments(longArgumentName1, longArgumentName2, longArgumentName3, longArgumentName4); // alternative format #2 retval = FunctionWithManyArguments( longArgumentName1, longArgumentName2, longArgumentName3, longArgumentName4); // [fmt05] -- prefer to break after a comma retval = anObject.SomeUsefulFunction(x.LeftMargin() + x.RightMargin(), x.TopMargin() + x.BottomMargin() - 1); // [fmt05] -- if that's not possible, break after an operator retval = anObject.SomeUsefulFunction(x.LeftMargin() + x.RightMargin() + anObject.HorizontalPadding(), x.TopMargin() + x.BottomMargin() - 1); return retval; } /** * !!! Loop formatting */ ARosetta.prototype.Loops = function() { // [fmt08] -- for() loop; note the pre-incremented form of the loop control for (var i = 0; i < kSomeConstant; ++i) { // loop code here... } var someBoolean = true; // [fmt09] while (someBoolean) { // useful code... } // [fmt09] -- while loop with an empty body makes the emptiness explicit while (this.SomeFuncReturningBool()) { // intentionally empty... } // [fmt10] -- do/while loop. // [fmt18] -- exception to the bracing rule saying that braces should // always be on a line by themselves do { // loop code here.. } while (someBoolean); } } |
Rosettas >