2

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;
};
2
  • Careful. Things change. Whatever you think about details of an instance implementation might not be true.
    – gnasher729
    Jul 4, 2015 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. :) Jul 4, 2015 at 15:04

1 Answer 1

1

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.

1
  • 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. Jul 6, 2015 at 3:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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