Apparently C allows a variable's initialization to refer to the variable being declared, as in
I guess the reasoning is that by the time the compiler reaches the initialization on the right side of the "=", the declaration on the left side has allocated memory for the variable, so the variable may be referenced.
This language feature may have its uses, but it can also lead to subtle bugs. I just fixed a bug that boiled down to the fact that the following compiled and ran:
- (void)wtf:(NSString *)ping
{
NSString *pong = [pong self];
NSLog(@"%@", pong);
} |
- (void)wtf:(NSString *)ping
{
NSString *pong = [pong self];
NSLog(@"%@", pong);
}
The first line of the method should of course have been
NSString *pong = [ping self]; // ping, not pong |
NSString *pong = [ping self]; // ping, not pong
but due to copy-paste and variables looking alike, I didn't spot the typo until our QA guy reported a crash and his stack trace led me to this method.
By coincidence, the code had worked correctly for me every time in development. In the debugger, I printed the value of pong on entry, and it happened to be the value of ping, presumably because that was the leftover value that happened to be on the stack.
I don't think this is a compiler bug. I believe the C standard allows the incorrect code I wrote, for two reasons. First, I created a scratch project and compiled the above wtf:
method verbatim with GCC 4.2, LLVM GCC 4.2, and LLVM compiler 1.7. Second, I vaguely remember someone posting a trick for creating variables with unique values for use as the "context" passed around by KVO. I think the trick used this feature of C.
Update: I think the KVO trick was something like
I guess there no reason to disallow this, since it's equivalent to
So now that I think about it, my bug wasn't really related to initialization. I could just as easily have made my mistake this way:
- (void)wtf:(NSString *)ping
{
NSString *pong;
pong = [pong self];
NSLog(@"%@", pong);
} |
- (void)wtf:(NSString *)ping
{
NSString *pong;
pong = [pong self];
NSLog(@"%@", pong);
}