Dot (".") operator and arrow ("->") operator use in C vs. Objective-C
Asked Answered
I

5

66

I'm trying to wrap my head around some of the differences in usage and syntax in C vs. Objective-C. In particular, I want to know how (and why) the usage differs for the dot operator and the arrow operator in C vs. Objective-C. Here is a simple example.

C Code:

// declare a pointer to a Fraction
struct Fraction *frac;

...

// reference an 'instance' variable
int n = (*frac).numerator;     // these two expressions
int n = frac->numerator;       // are equivalent

Objective-C Code:

// declare a pointer to a Fraction
Fraction *frac = [[Fraction alloc] init];

...

// reference an instance variable
int n = frac.numerator;        // why isn't this (*frac).numerator or frac->numerator??

So, seeing how frac is the same in both programs (i.e. it is a pointer to a Fraction object or struct), why are they using different syntax when accessing properties? In particular, in C, the numerator property is accessed with frac->numerator, but with Objective-C, it is accessed using the dot operator, with frac.numerator. Since frac is a pointer in both programs, why are these expressions different? Can anyone help clarify this for me?

Irresistible answered 31/1, 2012 at 0:12 Comment(1)
O
88

frac is actually not the same in both programs.

A C Fraction is a struct, which is a base type with no overloaded operators and is only really able to be constructed and destructed by default. If you define functions or fields on the struct, the way to access those properties in C is with the dot (.) operator. Objective-C maintains this operator when you use structs. For convenience, you can perform a dereference-and-dot operation using the arrow (->) operator (the two equivalent expressions you mention). Objective-C also preserves this when accessing structs.

An Objective-C Fraction in your example, however, is probably (one would assume) a pointer of at least type id, which is simply a classname and pointer to the instance of that class under the hood. It's also very likely to be a subclass of NSObject or NSProxy. These Objective-C classes are special in that they have a whole layer of predefined operations on top of just a C struct (if you really want to dig into it then you can take a look at the Objective-C Runtime Reference). Also important to note, an Objective-C class is always a pointer.

One of the most basic operations is objc_msgSend. When we operate on these types of objects, the Objective-C compiler interprets a dot (.) operator or the square bracket syntax ([object method]) as an objc_msgSend method call. For more detailed info about what actually happens here, see this series of posts by Bill Bumgarner, an Apple engineer who oversees the development of the Obj-C runtime.

The arrow (->) operator is not really supposed to be used on Objective-C objects. Like I said, Objective-C class instances are a C struct with an extra layer of communication added, but that layer of communication is essentially bypassed when you use the arrow. For example, if you open up Xcode and type in [UIApplication sharedApplication]-> and then bring up the method completion list, you see this:

A list of internal ivars on an Obj-C object when using the arrow operator

Here you can see a bunch of normal fields which we generally access with square bracket syntax (like [[UIApplication sharedApplication] delegate]). These particular items, however, are the C fields that store the values of their respective Objective-C properties.

So, you can roughly think of it like this:

Dot operator on a C object

  1. (at run time) Return value of the field

Arrow operator on a C object (pointer)

  1. Dereference pointer
  2. Return value of the field

Dot operator/square brackets on an Objective-C object (pointer)

  1. (at compile time) Replace with call to objc_msgSend
  2. (at run time) Look up Obj-C class definition, throw exception if something went wrong
  3. Dereference pointer
  4. Return value of the field

Arrow operator on an Objective-C object (pointer)

  1. (at run time) Dereference pointer
  2. Return value of the field

Now I'm definitely oversimplifying here, but to summarise: the arrow operators appear to do basically the same thing in both cases, but the dot operator has an extra/different meaning in Objective-C.

Outshine answered 31/1, 2012 at 1:9 Comment(3)
"Dot operator on a C object (at run time) Check field exists" No such run-time check is done. Nor will the arrow operator check for invalid pointers at runtime.Timmons
@Timmons Can you link to documentation which describes exactly what happens so I can edit the post accordingly? I don't have time to do the research myself. Thanks!Outshine
open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf see section 6.5.2.3, page 84 (numbered 72 in the PDF). You may need to be familiar with reading these sorts of documents in order to understand it.Timmons
J
9

Dot-notation is a design choice. Since we always deal with pointers to objc instances, I'd guess the designers wanted something familiar, which also would not break existing programs. It was introduced in ObjC 2 - just a few years ago. Before that, you always had to use brackets for messaging.

Dot notation makes a difference though - it is not direct access, but a message.

That is:

obj.property = val;
// is the same as:
[obj setProperty:val];
// and not:
obj->property = val;


val = obj.property;
// is the same as:
val = [obj property];
// and not:
val = obj->property;

You can still write obj->ivar to access a pointer to object's members (if visible).

Julieannjulien answered 31/1, 2012 at 0:18 Comment(0)
W
5

In your first example, Fraction is a struct. In your second example, Fraction is an Objective-C class (and in iOS would likely be a subclass of NSObject).

C++ does not allow overloading of operator .. Therefore without additional information you can deduce that the dot notation you're seeing is an additional language construct integrated into Objective-C, rather than a C/C++ defined or overloaded operator.

As it happens, the dot notation is simply a design feature the implementors chose as shorthand for property access, entirely equivalent to the square bracket getter:

myObjCVar.prop == [myObjCVar prop];
Widera answered 31/1, 2012 at 0:18 Comment(0)
P
2

The dot operator on objects is a special syntax for accessing objects' properties. It calls the property's getter or setter behind the scenes. So, for example, [@"hello" length] and @"hello".length are equivalent*. For all other types, the dot is the same as the C dot, and the arrow is always the same.

* Note: The accessor method won't always be named the same as the property. If it's a declared property and the declaration designates a special getter or setter method, that one will be used instead.

Pomiferous answered 31/1, 2012 at 0:18 Comment(1)
Note to whoever downvoted: If you think this answer contains wrong information, you're not correcting it just by hitting the down arrow. If you either edit the answer or leave a comment with the correct info, that's much more useful. Otherwise I'm just going to continue spouting off this info to whoever asks, because as far as I know it's all correct.Pomiferous
H
1

The dot and arrow notation are equally the same in C as it is in Objective-C (strict superset of ). I think the fundamental difference that needs to be distinguished is the difference between a struct and an Objective-C object.

The dot notation used for objects in Objective-C are used for properties that was introduced in Objective-C 2.0. However, with structs, the -> and dot notation between Objective-C and C are the same.

Haynie answered 31/1, 2012 at 0:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.