ObjC properties and C operators
Asked Answered
N

1

7

Given the following property declaration:

@property NSInteger foo;

How do the increment, decrement, and compound assignment operators actually work on self.foo?

It was my understanding that self.foo was merely syntactic sugar for the actual accessor methods. So self.foo isn't directly accessing an NSInteger variable called foo, but rather calling either:

- (void)setFoo:(NSInteger)foo;

or

- (NSInteger)foo;

Yet, the following set of code is perfectly fine, is not flagged, compiles fine, and returns exactly the expected results:

self.foo = 0;
NSLog(@"%d",self.foo); // prints 0

self.foo += 1;
NSLog(@"%d",self.foo); // prints 1

self.foo++;
NSLog(@"%d",self.foo); // prints 2

++self.foo;
NSLog(@"%d",self.foo); // prints 3

And I think it's probably safe to assume that the decrement pre and post fix operators as well as the other 9 compound operators will do exactly what you'd expect if you were using them directly on an NSInteger variable.

I just don't understand WHY it works if self.foo is truly just syntactic sugar for the two methods I mentioned above.

If I overwrite the default accessors to include NSLog statements so I can see when each is called and with what values, I can see that the getter is called first then the setter is called.

Does this mean that the following:

self.foo += 1;

is effectively replaced with this:

[self setFoo:([self foo] + 1)];

during precompilation?


EDIT: So, at the assembly level, is there any difference between self.foo += 1; and self.foo = self.foo + 1;? What if we're not talking about a property, and bar is just a regular int, at the assembly level is there a difference between bar += 1; and bar = bar + 1;?

Nels answered 1/5, 2014 at 21:59 Comment(4)
Exactly. Your assumption is correct.Avocet
Given the results, it seems clear that your assumption is correct.Gangster
I've added an addendum to my question to try clarifying what I'm actually getting at.Nels
@Nels I have added an answer of your question to my post. Please check.Avocet
A
6

Exactly. Your assumption is correct. You can implement property yourself and add logging to check your assumption one more time

In your @interface section:

@property(nonatomic) NSInteger foo; 
     // nonatomic keyword is not really required but 
     // it is better to add it since we will implement 
     // property as nonatomic

In @implementation section:

- (void)setFoo:(NSInteger)foo
{
    _foo = foo; // _foo variable is implicitly generated by compiler
    NSLog(@"set foo %d", _foo);
}

- (NSInteger)foo
{
    NSLog(@"get foo %d", _foo);
    return _foo;
}

Then run

self.foo = 0;
self.foo += 1;

you should receive in debug window:

set foo 0
get foo 0
set foo 1

UPDATE:

  • Re: "at the assembly level, is there any difference between self.foo += 1; and self.foo = self.foo + 1;?"

No. For both [self setFoo:([self foo] + 1)]; will be called.

  • Re: What if we're not talking about a property, and bar is just a regular int, at the assembly level is there a difference between bar += 1; and bar = bar + 1;?

Yes. But only if compile time optimization is turned off.

bar += 1; is faster. It will be compiled to something like:

mov eax,dword ptr [bar]
inc eax                // difference is here!
mov dword ptr [bar],eax

And bar = bar + 1; to:

mov eax,dword ptr [bar]
add eax,1              // difference is here!
mov dword ptr [bar],eax
Avocet answered 1/5, 2014 at 22:33 Comment(4)
So compound operators are a little misleading on Objective-C properties if you're expecting them to behave like they do in other languages. Can I assume the same assembly difference for non-properties with increment/decrement operators?Nels
@Nels not sure I understand you correctly. Can you clarify your question?Avocet
self.someVar++, someVar++, ++self.someVar, ++someVar, and minus as well.Nels
@Nels yes, they all have the same behaviour.Avocet

© 2022 - 2024 — McMap. All rights reserved.