4

If I'm not mistaken, structs mean objects, and struct pointers mean pointer to objects right? In an article, It says that classes are structs which means that they are objects.

Filter the list of all classes
The traditional definition of a class in Objective-C looks like this:

struct objc_class {
    Class isa;
    Class super_class;
    const char *name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;
    struct objc_method_list **methodLists;
    struct objc_cache *cache;
    struct objc_protocol_list *protocols;
    };

So, if it says that classes are structs, then how will they fit in the argument of objc_msgSend(id self, SEL_cmd) which requires a struct pointer which is of type id?

MiguelC
  • 298
  • 1
  • 3
  • 10
  • Do understand that there's a difference between a C++ "class" and "object" and the same terms in Objective-C. An Objective-C "object" is a very specific sort of structure that conforms to Objective-C specifications. It is implemented using C `struct` entities, but that fact can/should be ignored most of the time. C and `struct` are, in essence, the "assembly language" underlying Objective-C. – Hot Licks Oct 19 '13 at 21:01

2 Answers2

9

Classes are structs, but Class is a pointer type, being defined as

typedef struct objc_class *Class;

and this answers the first part of the question.

Now, if you take a look at <objc/objc.h> you'll find

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

 #if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

and in <obj/runtime.h> you'll find

/// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

meaning that in Objective-C 2.0 objc_object and objc_class are identical structs, both having an isa field.

That's why you can pass a Class where an id is required: classes are objects after all.

You would normally expect a warning about the incompatible pointers type, but apparently the Obj-C compiler uses an ad-hoc treatment this specific case. I have no references to support this, though.

EDIT

I finally found a reference in the clang source code:

In ASTContext.cpp, this is the Class declaration

TypedefDecl *ASTContext::getObjCClassDecl() const {
  if (!ObjCClassDecl) {
    QualType T = getObjCObjectType(ObjCBuiltinClassTy, 0, 0);
    T = getObjCObjectPointerType(T);
    TypeSourceInfo *ClassInfo = getTrivialTypeSourceInfo(T);
    ObjCClassDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
                                        getTranslationUnitDecl(),
                                        SourceLocation(), SourceLocation(),
                                        &Idents.get("Class"), ClassInfo);
  }
  
  return ObjCClassDecl;
}

and this is the id declaration

TypedefDecl *ASTContext::getObjCIdDecl() const {
  if (!ObjCIdDecl) {
    QualType T = getObjCObjectType(ObjCBuiltinIdTy, 0, 0);
    T = getObjCObjectPointerType(T);
    TypeSourceInfo *IdInfo = getTrivialTypeSourceInfo(T);
    ObjCIdDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
                                     getTranslationUnitDecl(),
                                     SourceLocation(), SourceLocation(),
                                     &Idents.get("id"), IdInfo);
  }
  
  return ObjCIdDecl;
}

In both cases the type is set to the result of getObjCObjectPointerType. This causes the compiler to consider both Class and id as pointers to Objective-C objects.

Community
  • 1
  • 1
Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
5

If I'm not mistaken, structs mean objects, and struct pointers mean pointer to objects right?

Mostly, yes. But since in Objective-C, objects (including classes) can only be manipulated using pointers, the shorthand "object" is used instead of a more correct "pointer to an object", even in pieces of official documentation.

So, if it says that classes are structs, then how will they fit in the argument of objc_msgSend()?

They pass a pointer to a struct which is an object. Class is a typedef for struct objc_class *, whereas id is a typedef for struct objc_object *. Both are (non-function) pointers, and both structures contain an isa field, they can be used interchangeably as far as you know what you are doing.

  • 1
    I wrote pretty much the same thing, but I have a doubt: why isn't the compiler throwing an `Incompatible pointer types` when you pass a `struct objc_class *` to a function expecting a `struct objc_object *`? Having an identical layout shouldn't matter at compiler time, so I would expect a warning. What's the trick? – Gabriele Petronella Oct 19 '13 at 18:32
  • @GabrielePetronella The trick is that the compiler knows that `Class` and `id` are special types. With the same reasoning, you could expect `objc_msgSend(@"foo", @selector(length))` to emit a warning, because `struct __NSCFConstantString *` is not compatible with `struct objc_object *`, but these are built-in types as well. –  Oct 19 '13 at 18:34
  • Thanks, this confirms my intuition. Do you have any reference to support this? – Gabriele Petronella Oct 19 '13 at 18:35
  • @GabrielePetronella Um, not any particular reference off the top of my head. You may find something interesting in the source of `clang`, though. –  Oct 19 '13 at 18:50
  • I understand. If I'll feel curious/patient enough during the afternoon I'll take a look at `clang`. +1 for the good answer, in any case. – Gabriele Petronella Oct 19 '13 at 18:53
  • @GabrielePetronella Thanks. Well if you wait, in the meantime I can search the sources as well :) –  Oct 19 '13 at 18:54
  • I you feel like, that would be really interesting :) – Gabriele Petronella Oct 19 '13 at 18:55
  • I think I found the relevant piece of code. Check it out in my answer ;) – Gabriele Petronella Oct 19 '13 at 20:47
  • Oh and by the way, to my knowledge `__NSCFConstantString` is a subclass of `NSObject`. So no big deal there. – Gabriele Petronella Oct 19 '13 at 21:42
  • @GabrielePetronella Well, yes, but `struct __NSCFConstantString *` and `struct objc_object *` are still incompatible types, with regards to the C type system. –  Oct 19 '13 at 21:45
  • sure but is `__NSCFConstantString` explicitly defined as a struct? I cannot find its declaration – Gabriele Petronella Oct 19 '13 at 21:46
  • @GabrielePetronella No, but all Objective-C objects are implicitly treated as a `struct` by the compiler. Even the GDB and LLDB debuggers adapt this convention, if I recall correctly. –  Oct 19 '13 at 21:50
  • I believe so. My point is simply that `__NSCFConstantString` is not a special case. Being a normal object is totally ok for the compiler not to emit any warning. I wouldn't expect `objc_msgSend(@"foo", @selector(length))` to emit a warning for instance. – Gabriele Petronella Oct 19 '13 at 23:00
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/39581/discussion-between-h2co3-and-gabriele-petronella) –  Oct 20 '13 at 05:00
  • just noticed the chat. I've added a few replies there. We definitely agree ;) – Gabriele Petronella Oct 25 '13 at 16:24
  • 1
    @GabrielePetronella Yay, that's nice! :) I've replied too. –  Oct 25 '13 at 16:40