super respondsToSelector

  • Anyone want to take a stab at explaining to me as thoroughly as
    possible why
    [super respondsToSelector: aSelector]

    doesn't actually do what it looks like it should do?

    Bonus points if you can explain why I can override the
    respondsToSelector:(SEL)aSelector method in my object and as long as I
    include the above line at the end of my overridden version my object
    reports back correctly that the object serves as a delegate and the
    delegate methods get called appropriately.

    It seems like either an infinite loop should occur if
    respondsToSelector is really being called on self, or it should return
    NO if it's called on super, in which case my delegate method in self
    should never get called.

    Puzzled.
  • On Sat, May 31, 2008 at 1:22 AM, Russ McBride <russ...> wrote:
    > It seems like either an infinite loop should occur if respondsToSelector is
    > really being called on self, or it should return NO if it's called on super,
    > in which case my delegate method in self should never get called.

    If you called respondsToSelector: on self inside of your
    respondsToSelector:, then yeah, that would be an infinite loop
    condition. Otherwise, calling respondsToSelector: on super should work
    like any other overridden method.

    The respondsToSelector: implementation in NSObject looks at the method
    table for the current class, not just the methods that are defined in
    NSObject. Perhaps that's where your confusion comes from. From the
    documentation:

    <file://localhost/Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/doc/uid/20000052-BBCEHCCE>

    "You cannot test whether an object inherits a method from its
    superclass by sending respondsToSelector: to the object using the
    super keyword. This method will still be testing the object as a
    whole, not just the superclass's implementation. Therefore, sending
    respondsToSelector: to super is equivalent to sending it to self.
    Instead, you must invoke the NSObject class method
    instancesRespondToSelector: directly on the object's superclass, as
    illustrated in the following code fragment."
  • On 30 May '08, at 11:22 PM, Russ McBride wrote:

    > Anyone want to take a stab at explaining to me as thoroughly as
    > possible why
    > [super respondsToSelector: aSelector]
    > doesn't actually do what it looks like it should do?

    Sure. "super" does not mean "my superclass". It means "self, but start
    looking for method implementations in my superclass".

    The purpose of "super" is to give you a way to call the inherited
    version of a method you've overridden, since there would otherwise be
    no way of doing so. The actual receiver of the method that's called
    via "super" is self, since "super" only changes the way in which
    methods are looked up.

    Since your class didn't override -respondsToSelector:, the
    implementation you get when you user "super" is the same as the normal
    one you'd get if you called it on self, i.e. the implementation in
    NSObject. And since the receiver is self, not some hypothetical
    instance of your superclass, you get the same result as if you'd
    called [self respondsToSelector:].

    If you actually want to ask a question of your class's superclass, you
    have to do so directly:
    [[[self class] superclass] instancesRespondToSelector: aSelector]

    —Jens
  • On 30 May 08, at 23:22, Russ McBride wrote:
    > Anyone want to take a stab at explaining to me as thoroughly as
    > possible why
    > [super respondsToSelector: aSelector]
    >
    > doesn't actually do what it looks like it should do?

    Keep in mind that, ordinarily, respondsToSelector: is implemented on
    NSObject. It does introspection of some sort on self - so [super
    respondsToSelector:...] is identical to [self respondsToSelector:...]
    unless you've implemented the method yourself.
  • On May 31, 2008, at 1:22 AM, Russ McBride wrote:
    >
    > Anyone want to take a stab at explaining to me as thoroughly as
    > possible why
    > [super respondsToSelector: aSelector]
    >
    > doesn't actually do what it looks like it should do?
    >
    > Bonus points if you can explain why I can override the
    > respondsToSelector:(SEL)aSelector method in my object and as long
    > as I include the above line at the end of my overridden version my
    > object reports back correctly that the object serves as a delegate
    > and the delegate methods get called appropriately.
    >
    > It seems like either an infinite loop should occur if
    > respondsToSelector is really being called on self, or it should
    > return NO if it's called on super, in which case my delegate method
    > in self should never get called.

    In general, sending a message to an object tells the Objective-C
    runtime to search for the proper implementation of that method.  The
    search starts at the real class of the object and proceeds up the
    inheritance chain through the superclasses.  It invokes the first one
    it finds.

    Sending a message to "super" tells the Objective-C runtime to do the
    same search, but start at the superclass of the class which defined
    the method which is currently executing.

    Now, if none of the classes in the inheritance chain have overridden -
    respondsToSelector:, then the only implementation to find (in either
    case) is the one provided by NSObject.  That implementation always
    behaves the same way -- it doesn't know and can't tell that it's been
    invoked on super (nor from what class's code that might have happened
    in).  It just does what it's designed to do: it determines if "self"
    responds to the given selector.

    So, a message to super _doesn't_ do any of the following:

    1) message a different object than self
    2) cause self to masquerade as a more limited or restricted version
    of itself (i.e. it doesn't actually change whether self responds to a
    given selector, even temporarily)
    3) invoke the implementation that's eventually found any differently
    than normal (i.e. there's no hidden parameter which passes along
    which class is "targeted")

    It just starts the search for the implementation in a different
    spot.  If both searches (starting from self's real class or starting
    from the superclass of the currently executing code) find the same
    implementation, then the result is identical.

    To do what you want, you can use [MySuperClass
    instancesRespondToSelector:aSelector].  Note, you have to name the
    specific class you want to check.  You can't use [self superclass]
    because that's dynamic -- the result from that may actually be deeper
    in the class hierarchy than the code you're writing.

    I hope that helps.

    Cheers,
    Ken
  • On May 30, 2008, at 11:43 PM, Jens Alfke wrote:
    > If you actually want to ask a question of your class's superclass,
    > you have to do so directly:
    > [[[self class] superclass] instancesRespondToSelector: aSelector]

    Well... yeah... you *can* do that.

    But *don't do that*.  (And I know Jens knows better -- I'm just
    pointing something out).

    Any code that relies upon *skipping* super's implementation of
    something to get something done is just asking for trouble.

    b.bum
  • Responding to myself:

    On May 31, 2008, at 1:52 AM, Ken Thomases wrote:
    > To do what you want, you can use [MySuperClass
    > instancesRespondToSelector:aSelector].  Note, you have to name the
    > specific class you want to check.  You can't use [self superclass]
    > because that's dynamic -- the result from that may actually be
    > deeper in the class hierarchy than the code you're writing.

    I was reminded by some googling that a better thing to do, rather
    than naming your superclass explicitly ("MySuperClass" in my example)
    is to name your own class explicitly and use the +superclass method
    to find the superclass:

    [[MyClass superclass] instancesRespondToSelector:aSelector]

    Cheers,
    Ken
  • On 30 May '08, at 11:55 PM, Bill Bumgarner wrote:

    > On May 30, 2008, at 11:43 PM, Jens Alfke wrote:
    >> If you actually want to ask a question of your class's superclass,
    >> you have to do so directly:
    >> [[[self class] superclass] instancesRespondToSelector: aSelector]
    >
    > Well... yeah... you *can* do that.
    >
    > But *don't do that*.  (And I know Jens knows better -- I'm just
    > pointing something out).
    >
    > Any code that relies upon *skipping* super's implementation of
    > something to get something done is just asking for trouble.

    No, that's not what it's for. There are situations where you implement
    a method, and you want to call the superclass implementation ... but
    only if there _is_ one, since otherwise that would raise an exception.

    This comes about with those @$&% "informal protocols" that pollute the
    namespace of NSObject. So for example, let's say I subclass
    NSFoobarControl and implement -awakeFromNib. Now, should I call [super
    awakeFromNib] first? If NSFoobarControl implements that method, then
    yes I'd damn better do so, otherwise I screw up the superclass's
    state. But if it doesn't, that super call will raise an exception.

    One solution is to put in the 'super' call, and then try running your
    code. If that call blows up, take it out. That's really brittle,
    though, since who knows if NSFoobarControl will change in 10.6 to have
    an -awakeFromNib method? If it does, suddenly my app might crash on
    10.6, and that might be really hard to track down.

    The only reasonable solution seems to be to do exactly what I said —
    check whether the superclass implements the method before calling it.

    —Jens
  • On Sat, May 31, 2008 at 2:52 PM, Ken Thomases <ken...> wrote:
    > To do what you want, you can use [MySuperClass
    > instancesRespondToSelector:aSelector].  Note, you have to name the specific
    > class you want to check.  You can't use [self superclass]  because that's
    > dynamic -- the result from that may actually be deeper in the class
    > hierarchy than the code you're writing.

    Just as a minor nit, it's probably better to write [[MyClass
    superclass] instancesRespondToSelector:...]. This variant will survive
    if you re-target your superclass and forget to change what it depends
    on. Both variants will still fail if you subject your code to
    copypasta without sufficient vetting.

    If you're adventurous and foolish you can extract your superclass
    without needing to hard-code any class names:

    #import <objc/objc-runtime.h>
    ...
    Class superclass = ((struct objc_super *)super)->class;

    But this is probably a poor idea to use in practice....

    Mike
  • On May 31, 2008, at 12:10 AM, Michael Ash wrote:

    > If you're adventurous and foolish you can extract your superclass
    > without needing to hard-code any class names:
    >
    > #import <objc/objc-runtime.h>
    > ...
    > Class superclass = ((struct objc_super *)super)->class;
    >
    > But this is probably a poor idea to use in practice....

    Why not simply:

    [[self superclass] instancesRespondToSelector:...]

    ?

    j o a r
  • On Sat, May 31, 2008 at 3:16 PM, j o a r <joar...> wrote:
    >
    > On May 31, 2008, at 12:10 AM, Michael Ash wrote:
    >
    >> If you're adventurous and foolish you can extract your superclass
    >> without needing to hard-code any class names:
    >>
    >> #import <objc/objc-runtime.h>
    >> ...
    >> Class superclass = ((struct objc_super *)super)->class;
    >>
    >> But this is probably a poor idea to use in practice....
    >
    >
    > Why not simply:
    >
    > [[self superclass] instancesRespondToSelector:...]
    >
    > ?

    Assume the following class hierarchy:

    A <- B <- C <- D <- E

    In the implementation of B, you write [self superclass]. Now your
    method executes with self set to an instance of E. What do you get?

    Mike
  • On May 31, 2008, at 12:23 AM, Michael Ash wrote:

    > Assume the following class hierarchy:
    >
    > A <- B <- C <- D <- E
    >
    > In the implementation of B, you write [self superclass]. Now your
    > method executes with self set to an instance of E. What do you get?

    I would propose that you should re-examine your design if you find
    that to be a problem in practice:

    <http://en.wikipedia.org/wiki/Code_smell>

    j o a r
  • On May 31, 2008, at 2:43 AM, j o a r wrote:
    >
    > On May 31, 2008, at 12:23 AM, Michael Ash wrote:
    >
    >> Assume the following class hierarchy:
    >>
    >> A <- B <- C <- D <- E
    >>
    >> In the implementation of B, you write [self superclass]. Now your
    >> method executes with self set to an instance of E. What do you get?
    >
    >
    > I would propose that you should re-examine your design if you find
    > that to be a problem in practice:
    >
    > <http://en.wikipedia.org/wiki/Code_smell>

    Using [self superclass] is wrong.  The hierarchy with five levels may
    or may not be a problem, but [self superclass] is still wrong even in
    a hierarchy with 3 levels (even if "A" is NSObject, as is typical).

    If your class may be subclassed, then [[self superclass]
    instancesRespondToSelector:aSelector] may blow up in your face.

    -Ken
  • On Sat, May 31, 2008 at 3:43 PM, j o a r <joar...> wrote:
    >
    > On May 31, 2008, at 12:23 AM, Michael Ash wrote:
    >
    >> Assume the following class hierarchy:
    >>
    >> A <- B <- C <- D <- E
    >>
    >> In the implementation of B, you write [self superclass]. Now your
    >> method executes with self set to an instance of E. What do you get?
    >
    >
    > I would propose that you should re-examine your design if you find that to
    > be a problem in practice:
    >
    > <http://en.wikipedia.org/wiki/Code_smell>

    As has been noted, this is a common problem in AppKit code. It happens
    any time you subclass a subclass of NSView and implement
    -awakeFromNib. If you then subclass that subclass (something which
    doesn't smell to me even a little bit) then the naive solution breaks
    badly.

    Mike
previous month may 2008 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