Tuesday, March 30, 2010

Objective-C Tuesdays: static variables in functions

Welcome back to Objective-C Tuesdays after a long hiatus. Picking up from where we left off, today we'll look at static variables declared at function scope.

Normal local variables are declared inside the body of a function:
int countCharInString(char c, char const *s) {
  int count = 0; // plain old local variable
  do {
    if (*s == c) ++count;
  } while (*s++);
  return count;
  // after we return, count ceases to exist
}
Plain old local variables exist only for the time that the function is executing. When the function returns, local variables vanish.

Sometimes you want to keep a value around between calls to a function. Typically you use a global variable for this, but if the variable is only ever used inside a single function, you can use a static variable declared inside the function instead. One common use for this is to automatically initialize a singleton object or data structure before its first use. For example:
// static variable declared in a function
NSArray *getDaysOfTheWeek() {
  static NSArray *daysOfTheWeek = nil;
  if ( ! daysOfTheWeek) {
    daysOfTheWeek = [[NSArray alloc] initWithObjects:@"Sunday",
                     @"Monday", @"Tuesday", @"Wednesday", 
                     @"Thursday", @"Friday", @"Saturday", nil];
  }
  return daysOfTheWeek;
}
The static variable daysOfTheWeek is actually a global variable and follows the same rules as global variables with one difference: it's only visible inside the getDaysOfTheWeek() function. This makes it seem like some magical kind of local variable that keeps its value between function calls, but in fact, you can rewrite getDaysOfTheWeek() to use a normal static global like this:
// same function using a static global variable instead
static NSArray *daysOfTheWeek = nil;

NSArray *getDaysOfTheWeek() {
  if ( ! daysOfTheWeek) {
    daysOfTheWeek = [[NSArray alloc] initWithObjects:@"Sunday",
                     @"Monday", @"Tuesday", @"Wednesday", 
                     @"Thursday", @"Friday", @"Saturday", nil];
  }
  return daysOfTheWeek;
}
There are only a couple of minor advantages to using a static variable declared in a function rather than a normal global:
  1. the static variable lives near the code that uses it
  2. global variable name clashes are avoided
However, because it's a global variable, it suffers from all the problems that global variables do. Code that make extensive use of global variables is often harder to understand and difficult to reuse. In a multithreaded application, global variables need to be carefully synchronized between threads to avoid data corruption and deadlocks. Global variables also make writing automated tests more difficult and sometimes even impossible. In general, it's best to avoid using global variables.

Next time, we'll take a look at local variables and function parameters.

No comments: