ActionScript

Rosetta.as

// 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

// !!! ActionScript3 - no preprocessor syntax !!!



// [nr25] the 'q' prefix indicates that we are controlling conditional

// !!! ActionScript3 - no precompilation macros !!!


// [sf07], only one class declared/defined in this source file.


// General Note about coding in Flex:

//

// Unlike most languages, Flex applications are written with a sometimes

// arbitrary combination of ActionScript3 and MXML. One can write a GUI class

// definition using ActionScript3 (Rosetta.as), or as an mxml file (RosettaView.mxml),

// with an accompanying script block (to implement the classes functions). In

// general, mxml is used for more static GUI components, and can often be thought

// of as the "View" portion of a component. It generally makes sense to implement

// at least some of the control logic in the mxml file, since one will be referencing

// objects identified in the mxml. This is how the Adobe examples are

// implemented. The Flex compiler actually converts/compiles the mxml into a class

// definition, so aside from the language peculiarities, there is no functional

// difference between a class defined in mxml vs. ActionScript3 (though there are some

// limitiations when defining a class using MXML - see Adobe documentation). One can

// inherit from a class defined in mxml, or extend in mxml a class defined in ActionScript3.

// This leaves the developer with a powerful myriad of choices about how to implement

// a class hierarchy.

//

// It's very possible and probable that this will be used in ways that some developers

// may not like. There are no absolutes, but as a general rule it's a good idea to

// keep ActionScript3 code in an MXML file to a reasonable minimum. This will encourage

// a clean separation of View code from control logic. It also has other benefits, such

// as keeping the static markup portion of the code, which may be more relevant to a

// graphic designer, separate from the C-style ActionScript3 code, which may confuse them.

//

// There are various techniques for organizing code in this way. A couple of good

// possibilities are a "code-behind" pattern, where the application control logic is

// implemented as a base class which the MXML extends. Alternatively, the bulk of the

// application control logic could extend the MXML.


package com.artlogic.devpractices.rosetta

{

// [sf05] Generally best to import individual classes

import flash.filesystem.File;

import mx.logging.Log;

import mx.logging.LogEventLevel;

/**

* Rosetta

* 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"

* !!! ActionScript3 - Unlike some other languages, the ActionScript3

* compiler expects the classname to match the filename. So classnames should

* not be prefixed with an 'A'. !!!

*

* [cas01] public member functions/methods listed first

* !!! ActionScript3 - Should be listed after Constructor function for clarity !!!

*/

public class Rosetta

{

// [nr08] new non-class types (enumerations, data structures, etc) are

// named with MixedCase and no special prefix

// [nr23] identifiers specifying constants for the program are always

// prefixed with a lowercase 'k'.

// !!! ActionScript3 - no enumeration syntax, constants declared as follows. !!!

public const kSomeConstant = 50;

public const kSomeOtherConstant = 100;


/**

* Construct the Rosetta object.

* !!! ActionScript3 - Although arguments can be passed into a constructor to

* initialize the object, it is usually better to have no arguments to the

* constructor, and use properties to initialize the object. This allows use

* of the object from MXML and makes serialization/deserialization of the

* object easier. !!!

*/

public function Rosetta()

{

}

// !!! ActionScript3 - No destructors in ActionScript3 !!!

// [cas01] public methods (functions) are declared first.

// !!! ActionScript3 - it's best to declare public properties before

//public functions.

// Note! Use explicit get and set properties, rather than creating

// functions like setFilename and getFilename in ActionScript3.

/**

* Set the filename to be used by this object.

* @param filename The filename.

*/

public function set filename (filename:String):void

{

fFilename = filename;

fInputFile = new File(filename);

}

/**

* [nr07] Member functions are named using CamelCase, with a leading

* upper case letter.

* !!! ActionScript3 - Like java, class methods

* (called functions in ActionScript3), begin with a lowercase letter. !!!

*/

public function memberFunctionWithMultipleWords():Boolean

{

var ok:Boolean = true;

// [fmt08] -- formatting of a for() loop.

for (var i:Number = 0; i < kSomeConstant; ++i)

{

for (var j:Number = 0; j < kSomeOtherConstant; ++j)

{

// [fmt02] -- preprocessor directives go in column zero.

// !!! ActionScript3 - No preprocessor directives. There ActionScript3 compiler does

// however support conditional compilation, controlled from build tool. !!!

// Note use of logger for verbosity control. Further initialization

// of the Log would be needed to actually use it this way...

Log.getLogger("Rosetta").log(LogEventLevel.INFO,

"testing: " + i + ", " + j);


// [nr07] -- Calls to member functions of the current object are

// made through an explicit this pointer.

ok = this.test(i, j);

if (!ok)

{

Log.getLogger("Rosetta").log(LogEventLevel.ERROR,

"Fatal error testing: " + i + ", " + j);

break;

}

}

if (!ok)

{

break;

}

}

return ok;

// [fmt02] -- labels used as the target of a goto are placed in column zero.

// !!! ActionScript3 - No goto or labels !!!

}


/**

* !!! Here's how we handle very long lines (i.e., longer than 79

* characters)

*/

public function longLineWrapping():Boolean

{

// [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:Boolean = SomeStaticClass.FunctionWithManyArguments(

longArgumentName1, longArgumentName2, longArgumentName3,

longArgumentName4);


// alternative format #1

retval = SomeStaticClass.FunctionWithManyArguments(longArgumentName1,

longArgumentName2,

longArgumentName3,

longArgumentName4);


// alternative format #2

retval = SomeStaticClass.FunctionWithManyArguments(

longArgumentName1,

longArgumentName2,

longArgumentName3,

longArgumentName4);


// [fmt05] -- prefer to break after a comma

retval = SomeStaticClass.SomeUsefulFunction(x.leftMargin(),

x.topMargin() + x.bottomMargin() - 1);


// [fmt05] -- if that's not possible, break after an operator

retval = SomeStaticClass.SomeUsefulFunction(x.LeftMargin() +

anObject.HorizontalPadding(), x.TopMargin() + x.BottomMargin() - 1);

return retVal;

}


/**

* !!! Loop formatting

*/

public function loops():void

{

// [fmt08] -- for() loop; note the pre-incremented form of the loop control

for (var i:Number = 0; i < kSomeConstant; ++i)

{

// loop code here...

}

// [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);

}


// [cas01] Protected member functions declared after public

/**

* [nr03] parameters passed to functions are named using lowerCamelCase

*/

protected function test(firstVal:Number, secondVal:Number):Boolean

{

var retval:Boolean = 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;

}

return retval;

}



// [cas01] Private member function declared after protected


/**

* Useful function to process something or other.

*/

private function process(val:Number):void

{

// [cg05] -- use '!!!' as a marker to indicate a section of code that

// requires attention

// !!!... removing old hardcoded value

// fProcessResult = 131;

// ...!!!

var result:Number = val;

while (--val)

{

result *= val;

}

fProcessResult = result;

}

/**

* Demonstrating the formatting of a switch statement.

*/

private function decide(midiEventType:Number):void

{

// [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:

// !!! ActionScript3 - Currently no native support for asserts.

// One could implement assert as a runtime error, and use the

// DEBUG configuration flag to compile out the implementation

// but there would be a performance hit. !!!

//ASSERT(false);

Log.getLogger("Rosetta").log(LogEventLevel.ERROR,

"Unsupported event type!");

break;

}

}


// [cas02] member variables declared in the same order: public, protected, private.

// [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed

// by an uppercase letter.

// !!! ActionScript3 - Applies only to protected and private variables. Public

// variables have no prefix, to enable later conversion to get/set function

// in a way that is transparent to clients of this class.

public var modValue:Number;

// [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed

// by an uppercase letter.

// !!! ActionScript3 - Applies only to protected and private variables. Public

// variables have no prefix, see above.

private var fFilename:String;


// [fmt28] -- when declaring pointer variables, attach the '*' to the

// typename, not the variable name.

// !!! ActionScript3 - All variables are "pointers" in ActionScript3 !!! //

private var fInputFile:File;

private var fProcessResult:Number = 0;


}

}

RosettaView.mxml

<?xml version="1.0" encoding="utf-8"?>

<!--

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.

This is a simple, and meaningless View component showing some of the style guide

formatting appropriate for MXML. Wherever it makes sense to do so, apply

ActionScript3 syntax to MXML.

-->

<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" width="400" height="300">

<mx:Script>

<![CDATA[

import com.artlogic.devpractices.rosetta.Rosetta;

// !!! ActionScript3/MXML - Formatting inside a script block should be treated

// identically to formatting in an ActionScript file. See Rosetta.as for

// more info.

/**

* Handle click event.

*/

private function onDoItClick(event:Event):void

{

// [nr07] -- Calls to member functions of the current object are

// made through an explicit this pointer.

// !!! ActionScript3 - This applies to public properties as well. All id'd

// members in MXML are defined as public properties.

var filename:String = this.filenameInput.text;

if ((null != filename) && (filename.length > 0))

{

//Create a Rosetta object

if (null == fRosetta)

{

fRosetta = new Rosetta();

}

//Initialize the filename property

fRosetta.filename = filename;

//Do something with the object.

fRosetta.memberFunctionWithMultipleWords();

}

}


// [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed

// by an uppercase letter.

private var fRosetta:Rosetta;

]]>

</mx:Script>

<mx:Text text="Enter filename below:"/>

<!-- [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed

by an uppercase letter.

!!! MXML - Public properties do not require (and should not have) an 'f' prefix.

Members defined in MXML are by definition public. !!!

-->

<mx:TextInput id="filenameInput" width="379"/>

<!--[nr07] -- Calls to member functions of the current object are

made through an explicit this pointer.

!!! MXML - Use the this. syntax when referencing member functions and

variables. !!!

-->

<mx:Button label="Do it!" width="161" click="this.onDoItClick(event)"/>

</mx:Panel>