|Home » Learning Curve » Developers Workshop
Coding So You Don't Look a Tosser
Programming is not a wannabe art - it's a science.
The GCC works differently than other compilers. It has its strong points and its weak points. Your responsibility is knowing where these are.
As Apple continue down the Road to Perdition (Intel) your code is going to have to be 'platform neutral' but if the PowerPC disappears you're going to have to take it into consideration.
The Intel CPU is a horrendously paraplegic processor. It has a dearth of onboard registers. When you're creating automatics you have to remember to use them all at once - otherwise that wheezing Intel CPU is going to be swapping them in and out of memory all the time.
This rarely happens with PowerPC builds because the PowerPC has more onboard registers than you can ever use. On rare occasions - perhaps less than 1% of the time - you'll see differences when you change the order of instructions, but most of the time you won't.
When testing your builds always keep an eye on the total size of your object code and your 'Release' executable. A tool like Xfind comes in very handy for this - in fact that's one of the reasons it was created. Just drop all your object files on one of its windows and read off the total bytes.
This will most often but not always correlate to the size of your executable, so be sure to check this as well. Your goal has to be to deliver the most compact and most efficient executable to your customer.
Automatics & Expressions
'Automatic' is the technical term for local variables you create on the stack - 'stack variables'. These must not be confused with 'compiler temporary variables' - and if you've read your Al Aho 'dragon books' you'll know the difference.
Your compiler is always creating a whole slew of temporary variables of its own to generate your code. Your goal has to be to reduce its workload.
Expressions such as the following are innocuous.
#define MYNUMBER (4 * 4096) // 4 clusters
This might not sound right given the strict definition of the macro preprocessor but it is: compilers of today - and already several years back - will compute these expressions at compile time. So there is no overhead. And you gain because it's easier for you to see what your code is doing.
String constants are another story. With the GCC you should never use global string constants. Never. However you will need your local string constants from time to time.
Using the string constant "foo" in a method or function is fine - just don't duplicate it in the same method or function, for the GCC will get messed up. If you need to use "foo" more than once in the same method or function, declare a local array instead.
char foo = "foo";
[And for heavens sake don't be a total dork and declare it as a 'char *' - that's what Microsoft programmers do and that's a sure sign you're a total tosser.]
[Note as well that the above character array is wasteful if "foo" is only used once.]
And the same applies to local NSString constants. Instead of using @"foo" twice in the same method or function, declare a local NSString constant.
NSString *foo = @"foo";
And again: if you only use @"foo" once then declaring an 'NSString *' is both overkill and wasteful.
The following is wasteful.
[[NSUserDefaults standardUserDefaults] setObject:object1 forKey:key1];
[[NSUserDefaults standardUserDefaults] setObject:object2 forKey:key2];
Now all you've been taught might tell you that's OK, right? But it's not. Ordinary expressions can carry an overhead and in the case of Objective-C methods you have the overhead of a message - seen by the Objective-C runtime as a function call. And as the most expensive thing in this super-efficient streamlined language is the function call - with its concomitant pushing onto the stack, popping at the destination, pushing back for the return, and popping finally with the caller - this is expensive.
The better way to do this is the following.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:object1 forKey:key1];
[defaults setObject:object2 forKey:key2];
Note that the message to the NSUserDefaults class method is only called once; in the previous example it was called twice - unnecessarily. And no, your compiler won't compensate for you here - you have to change your diaper on your own. The former snippet involves four tasks for the Objective-C runtime, the latter only three; the latter is both faster and more compact.
Finally - for now - don't create automatics if you don't need them. They will always represent an overhead and your compiler - GCC or not - will not compensate for your being a total tosser.
The following is Total Tosser Code™.
result = foo();
/* * */
If you don't need result for more than to check the return value of foo() then don't declare it.
/* * */
Your compiler won't compensate for your 'tosser tendencies' here - and if you thought about it you'd understand why: result is an automatic - a variable - and although you might find this strange, your compiler is presuming you're intelligent. So if you declare a local variable your compiler is presuming you'll use it.
Don't let your compiler down. Don't let your customer down either. Don't be a total tosser.
Software Reviews: The Very Ugly