I've been studying the Objective-C runtime for some years, and even hacked libobjc a little bit (both Apple's and GNUStep's), and I've been wondering about a design decision on the compilers.

Every Objective-C object is expected to have its size at least of sizeof(Class), having its first field being Class isa, as seem in struct objc_object. We see it's explictly declared in root classes like NSObject and old defunct Object. We also know that the runtime adds the pointer to the new objects when they are created by class_createInstance() (see code example below).

So, my question is: then why isn't the isa pointer automatically prepended to the class declarations? Why does it need them to declare it explictly even if that is error-prone?

Example with bad code:

#import <stdlib.h>
#import <stdio.h>
#import <objc/runtime.h>

@interface Foo {
  @public
  int x;
};
- (void)bar;
@end

@implementation Foo
- (void)bar {
  printf("bar\n");
};
@end

int main() {

  Class cls = objc_getClass("Foo");
  printf("cls = %p\n", cls);

  // Returns sizeof(int)
  printf("cls size = %ld\n", class_getInstanceSize(cls));

  Foo *obj = class_createInstance(cls, 0);
  printf("obj = %p\n", obj);

  // Are we saving isa?
  printf("hmm: %d\n", *((Class *)obj) == cls);

  // We are! This works ;)
  [obj bar];

  // Evil code
  obj->x = 10;

  // Did we do something wrong?
  printf("hmm: %d\n", *((Class *)obj) == cls);

  // Yeah, we did! Segfault here!
  [obj aaa];

  return EXIT_SUCCESS;
};
  • Careful. Things change. Whatever you think about details of an instance implementation might not be true. – gnasher729 Jul 4 '15 at 12:39
  • Well, when I first started playing with it, five years ago, the above behavior was already true, and caused a segfault. I tested it again yesterday to write this question, and same thing happened. I can't see any reasonable reasons isa is not implicit in root classes... so I'd like to know if there is any. :) – paulotorrens Jul 4 '15 at 15:04

It's an implementation detail of the Apple/GNUstep/OpenStep Objective-C runtime. libobjc is the Apple Objective-C runtime, and Cocoa/GNUstep classes like NSObject are tied to that Objective-C runtime.

Objective-C (originally) just adds a minimal layer of syntax on top of C, and there's no reason, from a pure Objective-C language point of view, that objects need to be laid out any particular way.

You could theoretically write your own Objective-C runtime that lay out objects and do other stuff differently, and then you write your own Objective-C framework, with your own root classes to work with that runtime.

  • I understand that, but... this doesn't seem a good reason. Clang has a separate code emitter for each Objective-C runtime (for Apple's libobjc4, for GNUStep's libobjc2...), so it knows which runtime you are using and it knows that the isa field is required. It could add it for you on root classes, or, at least, warn you when the first field is not a Class, to avoid broken code. – paulotorrens Jul 6 '15 at 3:12

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.