Class vs +class: Cocoa/Obj-C design question

  • Can I ask perhaps a "list in the mists of time" language/library
    question? (Or perhaps a dumb question--forgive me if so.)

    Why can't a class name (e.g., NSObject) stand for itself in general--
    i.e., why isn't NSObject == [NSObject class] the way +class is
    defined now?

    In theory, NSObject is a class object, and [NSObject class] should be
    its metaclass.

    Why this breakdown in what otherwise is a very clean language/library
    design?

    Cheers!
    --Chris Ryland / Em Software, Inc. / www.emsoftware.com
  • On Oct 13, 2007, at 12:17 PM, Chris Ryland wrote:
    > Can I ask perhaps a "list in the mists of time" language/library
    > question? (Or perhaps a dumb question--forgive me if so.)
    >
    > Why can't a class name (e.g., NSObject) stand for itself in general--
    > i.e., why isn't NSObject == [NSObject class] the way +class is
    > defined now?
    >
    > In theory, NSObject is a class object, and [NSObject class] should
    > be its metaclass.
    >
    > Why this breakdown in what otherwise is a very clean language/
    > library design?

    Classes can be every bit as dynamic as instances.

    Through posing or any of a number of other mechanisms, the 'isa'
    pointer of a class -- the thing returned by [NSObject class] -- can
    easily change at runtime.

    Thus, you should always use [ClassName class] or
    NSClassFromString(@"ClassName") to grab a reference to the class as
    doing so will always return the correct result regardless of what
    might have been dynamically loaded or modified since the original link.

    b.bum
  • On Oct 13, 2007, at 3:56 PM, Bill Bumgarner wrote:

    > On Oct 13, 2007, at 12:17 PM, Chris Ryland wrote:
    >> Can I ask perhaps a "list in the mists of time" language/library
    >> question? (Or perhaps a dumb question--forgive me if so.)
    >>
    >> Why can't a class name (e.g., NSObject) stand for itself in
    >> general--i.e., why isn't NSObject == [NSObject class] the way
    >> +class is defined now?
    >>
    >> In theory, NSObject is a class object, and [NSObject class] should
    >> be its metaclass.
    >>
    >> Why this breakdown in what otherwise is a very clean language/
    >> library design?
    >
    > Classes can be every bit as dynamic as instances.
    >
    > Through posing or any of a number of other mechanisms, the 'isa'
    > pointer of a class -- the thing returned by [NSObject class] -- can
    > easily change at runtime.
    >
    > Thus, you should always use [ClassName class] or NSClassFromString
    > (@"ClassName") to grab a reference to the class as doing so will
    > always return the correct result regardless of what might have been
    > dynamically loaded or modified since the original link.

    Bill--

    I appreciate that *instance* classes may change dynamically (e.g.,
    NSArray *array = [[NSArray alloc] init] may end up with array not
    being an actual NSArray instance but some subclass in the cluster),
    but are there real-life cases where a class itself (e.g., literally
    NSObject) can change its class? Where the literal expression
    [NSObject class] wouldn't be NSObject itself?

    I would think the more appropriate way to work around any language
    oddities with type names, etc. would be [NSObject self] to use a
    message to get at the class itself, rather than [NSObject class],
    which should, in theory, return the class of NSObject, i.e., its
    metaclass.

    Forgive me for pushing back (and I know you would know this, if
    anyone in the world would), but I'm still wondering (and perhaps
    still confused).

    Thanks &
    Cheers!
    --Chris Ryland / Em Software, Inc. / www.emsoftware.com
  • On Oct 15, 2007, at 9:47 PM, Chris Ryland wrote:
    > I appreciate that *instance* classes may change dynamically (e.g.,
    > NSArray *array = [[NSArray alloc] init] may end up with array not
    > being an actual NSArray instance but some subclass in the cluster),
    > but are there real-life cases where a class itself (e.g., literally
    > NSObject) can change its class? Where the literal expression
    > [NSObject class] wouldn't be NSObject itself?
    >
    > I would think the more appropriate way to work around any language
    > oddities with type names, etc. would be [NSObject self] to use a
    > message to get at the class itself, rather than [NSObject class],
    > which should, in theory, return the class of NSObject, i.e., its
    > metaclass.
    >
    > Forgive me for pushing back (and I know you would know this, if
    > anyone in the world would), but I'm still wondering (and perhaps
    > still confused).

    No worries -- There is a difference between claiming knowledge and
    showing code.

    Given that I'm currently in the "Show Me" state, here ya go!

    Given this:

    @interface Foo: NSObject
    @end
    @implementation Foo
    @end

    int main (int argc, const char * argv[]) {
        NSLog(@"Pre Pose NSObject--- %@: 0x%x", [NSObject class],
    [NSObject class]);
        NSLog(@"Pre Pose Foo-------- %@: 0x%x", [Foo class], [Foo class]);
        [Foo poseAsClass: [NSObject class]];
        NSLog(@"Post Pose NSObject-- %@: 0x%x", [NSObject class],
    [NSObject class]);
        return 0;
    }

    It'll spew this (edited for brevity):

    Pre Pose NSObject--- NSObject: 0xa07eccc0
    Pre Pose Foo-------- Foo: 0x3020
    Post Pose NSObject-- NSObject: 0x3020

    So, while "NSObject" still refers to the class "NSObject", posing
    effectively shoves "Foo" into the runtime in place of "NSObject".  It
    is sort of like the isa swizzling that occurs during KVO setup, but at
    the class level.

    Note that while posing is slimy, evil, and largely deprecated, there
    are any of a number of mechanisms that may now or in the future cause
    similar behavior within the runtime.

    As well, this requirement prevents the symbol referring to a class
    from getting baked into your binary (kinda like Java's class model).
    That is, the indirection gives the runtime considerably more
    flexibility with which to pursue optimizations or provide features.

    BTW: +class and +self are synonymous.  The metaclass is largely
    invisible in terms of the ObjC level API used to interrogate the
    runtime.  It can be confusing, too.

    b.bum
  • On 16/10/2007, at 1:39 PM, Bill Bumgarner wrote:

    > On Oct 15, 2007, at 9:47 PM, Chris Ryland wrote:
    >> I appreciate that *instance* classes may change dynamically (e.g.,
    >> NSArray *array = [[NSArray alloc] init] may end up with array not
    >> being an actual NSArray instance but some subclass in the
    >> cluster), but are there real-life cases where a class itself
    >> (e.g., literally NSObject) can change its class? Where the literal
    >> expression [NSObject class] wouldn't be NSObject itself?
    >>
    >> I would think the more appropriate way to work around any language
    >> oddities with type names, etc. would be [NSObject self] to use a
    >> message to get at the class itself, rather than [NSObject class],
    >> which should, in theory, return the class of NSObject, i.e., its
    >> metaclass.
    >>
    >> Forgive me for pushing back (and I know you would know this, if
    >> anyone in the world would), but I'm still wondering (and perhaps
    >> still confused).
    >
    > No worries -- There is a difference between claiming knowledge and
    > showing code.
    >
    > Given that I'm currently in the "Show Me" state, here ya go!
    >
    > Given this:
    >
    > @interface Foo: NSObject
    > @end
    > @implementation Foo
    > @end
    >
    > int main (int argc, const char * argv[]) {
    > NSLog(@"Pre Pose NSObject--- %@: 0x%x", [NSObject class],
    > [NSObject class]);
    > NSLog(@"Pre Pose Foo-------- %@: 0x%x", [Foo class], [Foo class]);
    > [Foo poseAsClass: [NSObject class]];
    > NSLog(@"Post Pose NSObject-- %@: 0x%x", [NSObject class],
    > [NSObject class]);
    > return 0;
    > }
    >
    > It'll spew this (edited for brevity):
    >
    > Pre Pose NSObject--- NSObject: 0xa07eccc0
    > Pre Pose Foo-------- Foo: 0x3020
    > Post Pose NSObject-- NSObject: 0x3020
    >
    > So, while "NSObject" still refers to the class "NSObject",
    > posing effectively shoves "Foo" into the runtime in place of
    > "NSObject".  It is sort of like the isa swizzling that occurs
    > during KVO setup, but at the class level.

    But, after posing, there's still no difference between using NSObject
    and [NSObject class] so it doesn't prove that there are cases where

    NSObject != [NSObject class]

    Can you think of another example that does?

    - Chris
  • On Oct 15, 2007, at 11:23 PM, Chris Suter wrote:
    > But, after posing, there's still no difference between using
    > NSObject and [NSObject class] so it doesn't prove that there are
    > cases where
    >
    > NSObject != [NSObject class]
    >
    > Can you think of another example that does?

    I'm not sure what you are asking.

    NSObject, by itself, cannot be used syntactically within Objective-C
    except as the target of method invocations.

    The following does not compile:

        NSLog(@"Foo 0x%x", NSObject);

    If the question is of a "what if" nature.  As in: "What if NSObject
    could be used as in a context like the above (or in NSObject ==
    NSArray)?", then the answer would be an implementation detail.

    Most likely, it would mean one of two things:

    (1) a bare "NSObject" would turn into an equivalent to [NSObject class]

    (2) a bare "NSObject" would turn into a value defined at link time to
    point to the NSObject class (likely through one level of indirection
    as per most dylib flavored symbols)

    If (1), then -- no -- no difference.

    If (2), then -- yes -- huge difference.

    If Objective-C on OS X were to support such a pattern, it would likely
    fall be in the style of (1).  It is consistent and will lead to
    implementations of least surprise.

    b.bum

    (Of course, a cached variable containing the result of [NSObject
    class] will quite nicely demonstrate the potential inconsistencies of
    (2)).
  • On 16/10/2007, at 2:51 PM, Bill Bumgarner wrote:

    > On Oct 15, 2007, at 11:23 PM, Chris Suter wrote:
    >> But, after posing, there's still no difference between using
    >> NSObject and [NSObject class] so it doesn't prove that there are
    >> cases where
    >>
    >> NSObject != [NSObject class]
    >>
    >> Can you think of another example that does?
    >
    > I'm not sure what you are asking.

    Well, the OP said:

    > Why can't a class name (e.g., NSObject) stand for itself in
    > general--i.e., why isn't NSObject == [NSObject class] the way
    > +class is defined now?

    to which you replied:

    > Classes can be every bit as dynamic as instances.
    >
    > Through posing or any of a number of other mechanisms, the 'isa'
    > pointer of a class -- the thing returned by [NSObject class] -- can
    > easily change at runtime.
    >
    > Thus, you should always use [ClassName class] or NSClassFromString
    > (@"ClassName") to grab a reference to the class as doing so will
    > always return the correct result regardless of what might have been
    > dynamically loaded or modified since the original link.

    and gave the example that you did.

    What I was trying to say was that it wasn't clear to me how your
    example and explanation answered the original question since after
    posing, [NSObject class] and NSObject are the same thing (where the
    compiler permits of course).

    e.g. after posing

    [NSObject alloc]

    and

    [[NSObject class] alloc]

    are identical.

    So, going back to the original question, is there a circumstance
    where NSObject isn't the same as [NSObject class]?

    - Chris
  • On Oct 16, 2007, at 12:19 AM, Chris Suter wrote:
    > So, going back to the original question, is there a circumstance
    > where NSObject isn't the same as [NSObject class]?

    Effectively, they are the same thing.

    Technically, they are never the same.  Bare "NSObject" can only be
    used for invoking class methods.  [NSObject class] produces a pointer
    to the class that can be used for messaging, comparison, etc...

    b.bum
  • On Oct 16, 2007, at 10:31 AM, Bill Bumgarner wrote:

    > On Oct 16, 2007, at 12:19 AM, Chris Suter wrote:
    >> So, going back to the original question, is there a circumstance
    >> where NSObject isn't the same as [NSObject class]?
    >
    > Effectively, they are the same thing.
    >
    > Technically, they are never the same.  Bare "NSObject" can only be
    > used for invoking class methods.  [NSObject class] produces a
    > pointer to the class that can be used for messaging, comparison,
    > etc...

    OK, thanks for explaining.

    Seems to me that the real issue here is that NSObject is just a
    typename in C, and not a pointer to the class, while the
    [NSObject ...] construct is defined to use any initial typename as a
    class object to which a method is sent.

    I'm noodling on the design of a fully dynamic Objective-C-like
    language for Cocoa where the simple name NSObject evaluates to a full-
    fledged object (no more C pointers in this language except at
    language-crossing boundaries), so in that case I could assert that
    NSObject === [NSObject class] === [NSObject self], both technically
    and effectively.

    But I sure wish [NSObject class] was defined to be the metaclass, and
    [NSObject self] were defined to be the class itself (to get around
    the C language limitation), as then when you're required to do
    metaclass munging, it all coheres.

    Cheers!
    --Chris Ryland / Em Software, Inc. / www.emsoftware.com
previous month october 2007 next month
MTWTFSS
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
Go to today