Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dot syntax vs method syntax with getter=

Tags:

objective-c

I'm not sure how much use this question is but it seems interesting to me...

I thought that using property/synthesize statements was equivalent to me creating the getter/setter. Therefore

// .h
@property (nonatomic) BOOL on;

// .m
@synthesize on = _on;

// In my mind synthesizes the following methods

// - (BOOL)on;
// - (void)setOn:(BOOL)on;

However if I change the declarations to the following:

                              v
@property (nonatomic, getter=isOn) BOOL on;

@synthesize on = _on;

// In my mind synthesizes the following

// - (BOOL)isOn;
// - (void)setOn:(BOOL)on;

Then given the above I override the getter so I know when it is called:

- (BOOL)isOn;
{
    NSLog(@"I was called");
    return _on;
}

Now calling the following on an instance (myClass) results in:

NSLog(@"%d", [myClass isOn]);

//=> 2012-02-09 22:18:04.818 Untitled[1569:707] I was called
//=> 2012-02-09 22:18:04.820 Untitled[1569:707] 1
    
NSLog(@"%d", myClass.isOn);
    
//=> 2012-02-09 22:18:24.859 Untitled[1599:707] I was called
//=> 2012-02-09 22:18:24.861 Untitled[1599:707] 1
    
NSLog(@"%d", myClass.on);         // This is the one I didn't expect to work
    
//=> 2012-02-09 22:18:55.568 Untitled[1629:707] I was called
//=> 2012-02-09 22:18:55.570 Untitled[1629:707] 1

I had always assumed that if I was using a property in this sense it was perfectly valid to use the getter/setter with dot syntax in the form

myClass.isOn;
myClass.on = on;

From another question it was suggested that when using dot syntax I should use the property name like this:

myClass.on   // Correct
myClass.isOn // Incorrect

Although this works it seem slightly less logical because I know there is no underlying method - (BOOL)on it is instead mapped to - (BOOL)isOn

My questions are (using the latter example)

  • Is this a bug or should myClass.on really be silently changed to call - (BOOL)isOn
  • Semantically speaking I am accessing state not invoking behaviour so is my current use of dot syntax correct? (e.g. myClass.isOn)

Update

Although no one has explicitly said it I have reasoned that using .isOn is bad form because regardless of the fact that under the hood the same method is called, semantically isOn is asking a question, which is more behaviour rather than state.

However I am still unclear on where the "magic" wiring goes on that turns calls to myClass.on into [myClass isOn]


Update 2

After looking around the docs some more I found this section on Declared Properties. Using the following code I can inspect a class' properties:

id MyClass = objc_getClass("MyClass");
unsigned int outCount, i;

objc_property_t *properties = class_copyPropertyList(MyClass, &outCount);
for (i = 0; i < outCount; i++) {
    objc_property_t property = properties[i];
    NSLog(@"Name: %s, attributes: %s\n", property_getName(property), property_getAttributes(property));
}

//=> 2012-02-10 07:10:28.333 Untitled[934:707] Name: on, attributes: Tc,GisOn,V_on

So we have the following attributes:

  • name = on
  • type = char (Tc)
  • getter = isOn (GisOn)
  • variable = _on (V_on)

With all of this information available at runtime it kind of leaves the question is this lookup done at runtime or compile time like some answers suggest?

like image 644
Paul.s Avatar asked Feb 09 '12 22:02

Paul.s


4 Answers

However I am still unclear on where the "magic" wiring goes on that turns calls to myClass.on into [myClass isOn]

The logic surely goes as follows, when compiling an obj.name in a getting context:

if(there is an accessible @property for name in scope)
{
   if(there is a custom getter specified)
      compile "[obj customGetter]"
   else
      compile "[obj name]"
}
else if (there is an an accessible instance method name in scope)
   compile "[obj name]"
else
{
   compile "[obj name]"
   warn obj may not respond to name
}

There are other ways a language/execution environment can handle custom getter names, but given that Obj-C puts the declaration in the header (which is public) the above is a good guess as to where the custom getter logic is performed - when compiling the call site.

like image 113
CRD Avatar answered Nov 15 '22 23:11

CRD


From your experiment we can infer that dot syntax is interpreted as follows:

  • is there a property with this name? If so, does it have a specified getter / setter name? if so, let's call that method.
  • otherwise, make up an appropriate method name (direct if we're getting, setXX if we're setting) and throw that at the receiver.

You can, for example, try to use .count against an NSArray instance. Before the abomination police kick in your doors, you may have time to see that it works.

To actually answer your question, in my mind dot notation should only be used to access properties, and in that case you should use the property name as declared in the interface. So .on for a UISwitch. I don't know why the getter name isn't given in the synthesize statement instead of the property declaration, it seems to belong in implementation rather than interface to me.

like image 20
jrturton Avatar answered Nov 16 '22 00:11

jrturton


Well concerning dot notation, let me cite Aaron Hillegass (Cocoa Programming for Mac OSX, 3rd. Ed):

"Overall, I think that this is a rather silly addition to the language since we already had a syntax for sending messages."

When you have a member variable on, and your getter for this variable is called isOn then .on and .isOn are two very different kind of things. By using the getter (and probably a setter, too) you will adhere to the "information hiding" promise, whereas by using direct access to the member variables you won't. Cocoa won't enforce those things as it is relying on conventions. It's up to you to decide which way is right for you. Considering convention, you would have to stick to setters and getters - no matter what names you give them, though.

like image 25
cli_hlt Avatar answered Nov 15 '22 23:11

cli_hlt


Property declarations are merely shorthand for regular method declarations. E.g.:

@property int color;
@property (getter=isOn) BOOL on;

becomes these method declarations:

- (int)color;
- (void)setColor:(int)value;
- (BOOL)isOn;
- (void)setOn:(BOOL)on;

You can call these methods just like any other method:

[foo color];
[foo isOn];

Likewise, dot notation is merely informal shorthand for calling plain old methods. For example:

x = @"Hello".length;
x = foo.on;
x = foo.isOn;

becomes

x = [@"Hello" length];
x = [foo isOn];
x = [foo isOn];

Note that @"Hello".length works even though NSString does not actually declare a property named "length". By default, foo.bar always expands to [foo bar] unless bar has been declared a property with a custom getter. If bar happens to be the name of a valid method then it will work without error.

Likewise, in your example foo.isOn works even though you don't actually declare a property named "isOn". Rather "isOn" is the name of a method that just happens to be the getter method for your "on" property.

So, while foo.isOn may work, it's considered bad form because isOn is not actually the name of the property.

What you cannot do is this:

x = [foo on]; // Error

because you never declare an on method.

like image 1
Darren Avatar answered Nov 16 '22 01:11

Darren