Rosettas‎ > ‎

Objective C


Rosetta.h

// Copyright (c) 2007 Art & Logic, Inc. All Rights Reserved.
// $Id: Rosetta.h,v 1.2 2008/03/03 20:55:04 jschindler Exp $

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

// [sf05]
// !!! #import preferred in objc over #include since it has implicit recursive include protection
#import "AlTypes.h"

// [nr25] the 'q' prefix indicates that we are controlling conditional
// compilation
#define qVerbose


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

/** 
* An enum.
* More detailed enum description.
*/
// [nr08] new non-class types (enumerations, data structures, etc) are
// named with MixedCase and no special prefix 
enum EnumName
{
   // [nr23] identifiers specifying constants for the program are always
   // prefixed with a lowercase 'k'.
   kSomeConstant = 50,
   kSomeOtherConstant = 100
};

/**
* @class ARosetta
* @brief 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"
// !!! All classes in objc should subclass NSObject
@interface ARosetta : NSObject 
{
   // [cas01] !!! Access levels not valid for methods
   // Private methods defined in implementation file (.m) using a category (optional)


   // [cas02] member variables declared in the same order: public 
   // (avoid in most languages), protected, private.
   // !!! private by default in objc
@public

@protected

@private
   // [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed 
   // by an  uppercase letter.
   NSString*      fFilename;
   // [fmt28] -- when declaring pointer variables, attach the '*' to the
   // typename, not the variable name.
   NSFileHandle*  fInputFile;

   SInt32         fProcessResult;
}

//Properties do not need the 'f' prefix.  There is no need to define a member variable 
//unless you need one.
@property (nonatomic, strong) path;
//[nr04] You can also define member variables like this.  Use the prefix 'f' when
//you override the default.
@property (nonatomic, strong) path=fPath;


/**
* Initialize the Rosetta object.
* @param fileName The file to use as our data source.
*/
-(id)InitWithFileName:(NSString*)fileName;

/**
* Destroy the Rosetta object, performing any needed cleanup.
*/
-(void)dealloc;

/**
* Member function does things.
* @return YES if successful, NO otherwise.
*/
/**
   * [nr07] In objc, class methods (other than a class' constructor) begin with 
   * a lowercase letter, and additional words in the method name are capitalized.
*/
-(BOOL)memberFunctionWithMultipleWords;

// !!! Here's how we handle very long lines (i.e., longer than 79
// characters)
-(BOOL)longLineWrapping;

// !!! Loop formatting
-(void)loops;

// [nr03] parameters passed to functions are named using lowerCamelCase
// !!! Note the label for the second parameter, making the calling convention
// more descriptive in objc
-(BOOL)testWithFirstVal:(SInt32)firstVal andSecondVal:(SInt32)secondVal;

@end

Rosetta.m

// Copyright (c) 2008 Art & Logic, Inc. All Rights Reserved.
// $Id: Rosetta.m,v 1.3 2008/03/20 19:41:36 bporter Exp $

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

#import "Rosetta.h"

/**
* Category for private methods.
*/
@interface ARosetta (Private)

/**
* Useful function to process something or other.
* @param val What val is.
*/
-(void)process:(SInt32)val;

// Demonstrating the formatting of a switch statement.
-(void)decide:(UInt8)midiEventType;

@end

@implementation ARosetta (Private)

-(void)process:(SInt32)val
{
   // [cg05] -- use '!!!' as a marker to indicate a section of code that
   // requires attention
   // !!!... removing old hardcoded value
   // fProcessResult = 131;
   // ...!!!
   SInt32 result = val;
   while (--val)
   {
      result *= val;
   }
   
   fProcessResult = result;
}

-(void)decide:(UInt8)midiEventType
{
   // [fmt11] -- switch/case formatting.
   switch (midiEventType)
   {
      // comments precede the case
      case kNoteOn:
         [self NoteOn:now];
         if (duration > 0)
         {
            [self noteOff:now + duration];
         }
         break;
         
      case kNoteOff:
         [self NoteOff:now];
         break;
         
      case kPolyAfter:
         after = channelValue;
         // [fmt35] include, but comment out the break when falling through intentionally.
         // break;
         
      case kChannelAfter:
         [self 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:
         NSAssert(false, @"Unsupported event type!");
         [self LogError:@"Unsupported event type!"];
         break;
   }
}

@end

@implementation ARosetta

-(id)initWithFileName:(NSString*)fileName
{
   // !!! only proceed with initialization if our super init succeeds
   if (nil != (self = [super init]))
   {
      fFileName = [fileName copy];     // !!! make our own local copy
      fInputFile = [[NSFileHandle fileHandleForReadingAtPath:fileName] retain];     // !!! retain autorelease object
      fProcessResult = 0;
   }
   
   // !!! make sure you return self!
   return self;
}

-(void)dealloc
{
   [fFileName release];
   [fInputFile release];
   
   // !!! must call super's dealloc
   [super dealloc];
}

-(BOOL)memberFunctionWithMultipleWords
{
   BOOL ok = true;
   SInt32 i;
   SInt32 j;
   
   // [fmt08] -- formatting  of a for() loop.
   // !!! note that gcc by default doesn't allow the loop variable definition inside the for statement
   for (i = 0; i < kSomeConstant; ++i)
   {
      for (j = 0; j < kSomeOtherConstant; ++j)
      {
// [fmt02] -- preprocessor directives go in column zero.         
#ifdef qVerbose
         NSLog(@"testing: %d, %d", i, j);
#endif
         // [nr07] -- Calls to member functions of the current object are
         // made through an explicit this-> pointer.
         ok = [self test:i :j];
         if (!ok)
         {
            NSLog(@"Fatal error testing: %d, %d", i, j);
            goto CleanUp;
         }
      }
   }
   return true;

// [fmt02] -- labels used as the target of a goto are placed in column zero.
CleanUp:
   // cleanup code here...
   return false;
}

-(BOOL)longLineWrapping
{
   // [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
   retval = [self functionWithManyArguments:longArgumentName1
                                       Arg2:longArgumentName2
                                       Arg3:longArgumentName3
                                       Arg4:longArgumentName4];
}

-(void)loops
{
   // [fmt08] -- for() loop; note the pre-incremented form of the loop control 
   int i;
   for (i = 0; i < kSomeConstant; ++i)
   {
      // loop code here...
   }

   // [fmt09]
   while (someBoolean)
   {
      // useful code...
   }

   // [fmt09] -- while loop with an empty body makes the emptiness explicit
   while ([self 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);
}

-(BOOL)testWithFirstVal:(SInt32)firstVal andSecondVal:(SInt32)secondVal
{
   bool 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
      // [self Process:firstVal];
      // $$$ after
      // Shouldn't this be processing the first value in this case?
      [self Process:firstVal];
      // $$$ end
   }
   else if (secondVal > kSomeConstant)
   {
      [self 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;
}

@end