1

I've been teaching myself Objective-C via some lectures from iTunes U.

I like the course, but the professor routinely writes code like this:

while (index < [self.textToAnalyze length]) {
    NSRange range;
    id value = [self.textToAnalyze attribute:attributeName atIndex:index effectiveRange:&range];
    ....
}

I have mostly worked in C and C++, and there are a couple of things about this code that seem glaringly wrong to me from a performance / style perspective.

  1. The code declares two variables (of type NSRange and id) inside the loop. A naive compiler would reserve space for each of these types of variables at each iteration through the loop.

  2. The code calls the length selector ([self.textToAnalyze length]) in the loop condition. As the programmer, I know that the length of the textToAnalyze property does not change while the loop is iterating. However, I'm not convinced that the compiler will know this. Won't this code call the length selector every single iteration of the loop?

I know that compilers can be very crafty, but I think it is bad code to declare variables within a loop and call functions within the loop conditions. It could affect the performance, and in my mind, it is certainly poor style.

However, I am new to Objective-C, so here is my question: Is this bad code, or are these Objective-C idioms that are fine to use?

Phil Braun
  • 581
  • 2
  • 8
  • 19
  • 3
    Narrowing the scope of variables to the smallest section of code you need them is generally a good practice, not a bad one, so you should feel happy about declaring variables in a loop. You don't get a separate stack for each loop, so the compiler is unlikely to ever generate new ones every iteration. Unnecessarily calling functions in a condition is not so good, however. – Crowman May 23 '14 at 21:37
  • 3
    I had the same misconceptions as you when I graduated from my university. Your priority when writing code is to make it as clean and understandable as possible. Only once you've written the clean version, and you've proved that the code is a bottleneck, should you consider optimizing for performance. – CrimsonChris May 23 '14 at 22:55
  • 1
    Right. "Premature optimization is the root of all evil." This is a great answer. – Phil Braun May 23 '14 at 23:56

2 Answers2

3

The answer is: it depends.

For variables in loops, moving them out of the loop might improve performance of the loop, but now you've changed the scope and effected performance in another way. Which is better is definitely going to be situation-based.

But, as far as I'm concerned, a variable with a scope any wider than necessary is bad practice. Variables with unnecessarily wide scope and lead to user error. The amount of performance improvement you might get here is not worth ANY amount of debugging that could've been avoided with a narrower variable scope.

As for calling methods in loop conditions, again, this depends.

I'm quite certain that the length method of NSString is quite optimized. The length of a string is not analyzed every time length is called, and especially not so for NSString (as opposed to NSMutableString. If we're talking about an immutable string, calling length is simply returning an NSInteger value stored within the class and performance will be fine.

If, however, we're talking about an immutable string, we need to call length every time if it's important that we're only within the length of the string.

It's a mutable string. Even if this loop doesn't modify the string, it can be modified else where by anyone that has a reference to it. If you're concerned about performance, make an immutable copy of the string and use that immutable copy in the loop.


[myString length]

According to this answer, for both mutable and immutable versions, there is a variable within the class that stores the string's length. For immutable strings, this is calculated when the string is created and never changed. For mutable strings, this variable is calculated and set each time the string changes. At the end of the day, when you call string, it's purely returning the value of an internally stored int value in the class and will not be any slower than storing this length in a separate variable before the loop and comparing against this.

Community
  • 1
  • 1
nhgrif
  • 61,578
  • 25
  • 134
  • 173
0

I think it is theoretically possible for some loop conditions to be cached, but in practice that doesn't seem to happen — the length method will be called every time through the loop.

Does that make this bad code? Not necessarily. The overhead of a function call is not that huge. If this loop needs to be tight, then yes, caching the string's length is a great idea. But in many cases, it just doesn't make any measurable difference, so less code is better code.

As for declaring variables in a loop, that isn't problematic. There are two mainstream Objective-C compilers in existence, and neither has any trouble compiling that to efficient code. I doubt even POC has trouble with that. Muddling your variables' scope just to please a hypothetical awful compiler isn't good code — it's premature optimization. (Incidentally, the same holds true for C++ too.)

Community
  • 1
  • 1
Chuck
  • 234,037
  • 30
  • 302
  • 389