-
-
Save mattmassicotte/3150651 to your computer and use it in GitHub Desktop.
// clang -framework Foundation -c properties.m | |
#import <Foundation/Foundation.h> | |
@interface PropertyBug : NSObject { | |
NSString* _value; | |
} | |
@property (copy) NSString* value; | |
@end | |
@implementation PropertyBug | |
@synthesize value = _value; | |
@end | |
int main(const int argc, const char** argv) { | |
PropertyBug* object; | |
object = [PropertyBug new]; | |
// this should be an error... | |
if (object.value = nil) { | |
NSLog(@"dot-sytnax"); | |
} | |
// ... if it really is equivalent to this | |
if ([object setValue:nil]) { | |
NSLog(@"traditional"); | |
} | |
return 0; | |
} |
That actually makes convoluted sense. Mutating a structure via dot/arrow notation linguistically (according to traditional C semantics) implies directly setting the lval as opposed to calling a method, and returns the value that was set (which is the lval or the rval—they are equivalent because the assignment operator doesn't fail).
Setter methods are expected to return void
(and again, the assignment operator in C does not fail), so the runtime makes the (relatively safe) assumption that the object's setter also doesn't fail and wraps the call to return the boolean value of the argument to the setter, thus providing a condition as expected by C assignment semantics.
The inconsistency is that the runtime should be using object.value
as the value to cast (in case of a setter failure), not the argument to the setter. I'd say it's a runtime bug, but it's probably intentional since your getter could be custom (and also result in odd side effects—you have a failing setter so your getter is probably too clever for its own good, too), so using the rval is the safest approach since you can easily capture its pointer (or value, if a POD type) without causing any side effects.
Really, the problem is that a runtime engineer was clever :)
Perhaps even more fascinating is that "if (object.value = nil)" evaluates to false, and "if (object.value = @"abc")" evaluates to true, even if object.value is hard-coded to always return nil. This construct is really bizarre, and appear to disagree with traditional C semantics.