Why does the Objective-C compiler need to know at compile-time the signature of the methods that will be invoked on objects when it could defer that to runtime (i.e., dynamic binding)? For example, if I write [foo someMethod]
, why it is necessary for the compiler to know the signature of someMethod
?

- 63,694
- 13
- 151
- 195

- 964
- 11
- 24
-
1As I understand it, Objc likes to catch such potential errors before runtime (as it would result in a crash), so it puts heavier emphasis on pre-compile error checking. – Louis Tur Jan 05 '15 at 19:13
-
If you declare a pointer to point to an object of a particular class, the compiler will verify that that class implements any methods called using the pointer. If you declare it to be simply `id`, the compiler will only verify that the named method exists *somewhere*. – Hot Licks Jan 05 '15 at 19:27
-
1Excellent first question; welcome to Stack Overflow! – tenfour Jan 05 '15 at 21:14
1 Answers
Because of calling conventions at a minimum (with ARC, there are more reasons, but calling conventions have always been a problem).
You may have been told that [foo someMethod]
is converted into a function call:
objc_msgSend(foo, @selector(someMethod))
This, however, isn't exactly true. It may be converted to a number of different function calls depending on what it returns (and what's returned matters whether you use the result or not). For instance, if it returns an object or an integer, it'll use objc_msgSend
, but if it returns a structure (on both ARM and Intel) it'll use objc_msgSend_stret
, and if it returns a floating point on Intel (but not ARM I believe), it'll use objc_msgSend_fpret
. This is all because on different processors the calling conventions (how you set up the stack and registers, and where the result is stored) are different depending on the result.
It also matters what the parameters are and how many there are (the number can be inferred from ObjC method names unless they're varargs... right, you have to deal with varargs, too). On some processors, the first several parameters may be put in registers, while later parameters may be put on the stack. If your function takes a varargs, then the calling convention may be different still. All of that has to be known in order to compile the function call.
ObjC could be implemented as a more pure object model to avoid all of this (as other, more dynamic languages do), but it would be at the cost of performance (both space and time). ObjC can make method calls surprisingly cheap given the level of dynamic dispatch, and can easily work with pure C machine types, but the cost of that is that we have to let the compiler know more specifics about our method signatures.
BTW, this can (and every so often does) lead to really horrible bugs. If you have a couple of methods:
- (MyPointObject *)point;
- (CGPoint)point;
Maybe they're defined in completely different files as methods on different classes. But if the compiler chooses the wrong definition (such as when you're sending a message to id
), then the result you get back from -point
can be complete garbage. This is a very, very hard bug to figure out when it happens (and I've had it happen to me).
For a bit more background, you may enjoy Greg Parker's article explaining objc_msgSend_stret and objc_msgSend_fpret. Mike Ash also has an excellent introduction to this topic. And if you want to go deep down this rabbit hole, you can see bbum's instruction-by-instruction investigation of objc_msgSend. It's outdated now, pre-ARC, and only covers x86_64 (since every architecture needs its own implementation), but is still highly educational and recommended.

- 286,113
- 34
- 456
- 610
-
1Okay I see, i've seen in a post that the objective-c compiler uses the methode signature to cast objc_msgSend() before calling . for example int result = [obj foo:@"hello"]; is converted to int result = ((int (*)(id, SEL, NSString *))objc_msgSend)(obj, @selector(foo:), @"hello"); is that true ? – Zack ISSOIR Jan 06 '15 at 16:45
-
1[link](https://www.mikeash.com/pyblog/friday-qa-2009-03-20-objective-c-messaging.html) please see this article . – Zack ISSOIR Jan 06 '15 at 16:50
-
That's correct, though you shouldn't misread this. Casting is just "treat these bytes as this type." It's something that happens at compile time, not runtime (it's not a conversion). It's a statement that "an int will be returned" not "turn this into an int." Read carefully Mike's box that includes the words "Bad Things Happen." Mike is also glossing over the special cases for struct and floating point returns, which are architecture specific and not required for the point he's making. You may be further interested in https://mikeash.com/pyblog/friday-qa-2012-11-16-lets-build-objc_msgsend.html – Rob Napier Jan 06 '15 at 17:40
-
-
For those who have already floated gently to the bottom of the rabbit hole, the [current versions of `objc_msgSend()` are open source](http://opensource.apple.com/source/objc4/objc4-646/runtime/Messengers.subproj/). – jscs Jan 06 '15 at 19:32