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