[NSMutableArray array]

  • Is is safe to do [NSMutableArray array], even with the "array" class
    method is actually declared as +[NSArray array]. In other words, is it
    safe to call a super-class' class method.

    If not, why?

    If so, why? And also, is it generally safe in _all_ cases, or only
    just when specifically crafted to work?

    Many thanks,
    -Patrick
  • Yes, that is safe to use.  It's safe to use because classes are really just special objects, which means they get all the class method inheritance that instances get with instance methods.  This will work in every case where the implementors have used:

    [[[self alloc] init] autorelease]  //this will instantiate a new instance of whatever class invokes this method

    Instead of

    [[[MyClass alloc] init] autorelease]  //this will instantiate a new instance of MyClass, regardless of which class invoked this method

    Just like in instance methods, class methods have an implicit "self" variable that refers to the Class itself.

    Beyond that, NSMutableArray and NSArray are really just the same class (NSCFArray, usually), with mutability determined by an internal flag.

    Cheers,

    Dave

    On Apr 8, 2010, at 8:20 AM, Patrick M. Rutkowski wrote:

    > Is is safe to do [NSMutableArray array], even with the "array" class
    > method is actually declared as +[NSArray array]. In other words, is it
    > safe to call a super-class' class method.
    >
    > If not, why?
    >
    > If so, why? And also, is it generally safe in _all_ cases, or only
    > just when specifically crafted to work?
    >
    > Many thanks,
    > -Patrick
  • Ah, hmm; well in the case of them both being NSCFArray's, that does
    sound right; thanks :-)

    What I was worried about is that maybe NSMutableArray (or any
    sub-class in general) would need to do some special sub-class-specific
    initialization, which it might not have implemented. I guess though,
    if you're going to be sub-classing a class, then you ought to
    generally make sure that all of it's static method will work on your
    new sub-class?

    There's always the danger that the super-class will have new static
    methods added without your knowledge though.

    -Patrick

    On Thu, Apr 8, 2010 at 10:25 AM, Dave DeLong <davedelong...> wrote:
    > Yes, that is safe to use.  It's safe to use because classes are really just special objects, which means they get all the class method inheritance that instances get with instance methods.  This will work in every case where the implementors have used:
    >
    > [[[self alloc] init] autorelease]  //this will instantiate a new instance of whatever class invokes this method
    >
    > Instead of
    >
    > [[[MyClass alloc] init] autorelease]  //this will instantiate a new instance of MyClass, regardless of which class invoked this method
    >
    > Just like in instance methods, class methods have an implicit "self" variable that refers to the Class itself.
    >
    > Beyond that, NSMutableArray and NSArray are really just the same class (NSCFArray, usually), with mutability determined by an internal flag.
    >
    > Cheers,
    >
    > Dave
    >
    > On Apr 8, 2010, at 8:20 AM, Patrick M. Rutkowski wrote:
    >
    >> Is is safe to do [NSMutableArray array], even with the "array" class
    >> method is actually declared as +[NSArray array]. In other words, is it
    >> safe to call a super-class' class method.
    >>
    >> If not, why?
    >>
    >> If so, why? And also, is it generally safe in _all_ cases, or only
    >> just when specifically crafted to work?
    >>
    >> Many thanks,
    >> -Patrick

    >
  • On Apr 8, 2010, at 7:35 AM, Patrick M. Rutkowski wrote:

    > What I was worried about is that maybe NSMutableArray (or any
    > sub-class in general) would need to do some special sub-class-specific
    > initialization, which it might not have implemented.

    That's taken care of by the initializer methods (-init etc.) Every
    class should have a "designated initializer" method that the other
    initializers call first. Subclasses should override at least that
    designated initializer to add their own initialization code. That
    ensures all initializers and factory methods will set up the object
    correctly.

    > There's always the danger that the super-class will have new static
    > methods added without your knowledge though.

    Yes, in general that can be a problem. Usually it's not an issue when
    the classes are part of the same project/framework, as the base
    collection classes are. But if you're subclassing an external class
    and making some significant changes in its behavior, you might run
    into issues. In practice, though, this usually only happens if you're
    trying to do sneaky things to hack framework classes to do things they
    weren't meant to do...

    —Jens
  • On Apr 8, 2010, at 7:35 AM, Patrick M. Rutkowski wrote:

    > What I was worried about is that maybe NSMutableArray (or any
    > sub-class in general) would need to do some special sub-class-specific
    > initialization, which it might not have implemented. I guess though,
    > if you're going to be sub-classing a class, then you ought to
    > generally make sure that all of it's static method will work on your
    > new sub-class?
    >
    > There's always the danger that the super-class will have new static
    > methods added without your knowledge though.

    There is no such thing as a static method in Objective-C;  there are class methods and instance methods.  Class methods are inherited just like instance methods.

    Thus, when you say [NSMutableArray array], NSMutableArray's implementation of +array will be invoked (if it exists), regardless of whether or not said method is declared in the @interface of NSMutableArray.

    b.bum
  • Agreed, but there's always the danger the +array method, which might
    actually be implemented in NSArray.m, will not properly initialize the
    more specific NSMutableArray object.

    Of course, in this specific case that's the case, but it might be the
    case with other class hierarchies.

    But, nonetheless I'm troubled that nobody in this thread has
    acknowledged that yet :-o

    -Patrick

    On Thu, Apr 8, 2010 at 12:37 PM, Bill Bumgarner <bbum...> wrote:
    >
    > On Apr 8, 2010, at 7:35 AM, Patrick M. Rutkowski wrote:
    >
    >> What I was worried about is that maybe NSMutableArray (or any
    >> sub-class in general) would need to do some special sub-class-specific
    >> initialization, which it might not have implemented. I guess though,
    >> if you're going to be sub-classing a class, then you ought to
    >> generally make sure that all of it's static method will work on your
    >> new sub-class?
    >>
    >> There's always the danger that the super-class will have new static
    >> methods added without your knowledge though.
    >
    > There is no such thing as a static method in Objective-C;  there are class methods and instance methods.  Class methods are inherited just like instance methods.
    >
    > Thus, when you say [NSMutableArray array], NSMutableArray's implementation of +array will be invoked (if it exists), regardless of whether or not said method is declared in the @interface of NSMutableArray.
    >
    > b.bum
    >
    >
  • On 8 Apr 2010, at 12:21 PM, Patrick M. Rutkowski wrote:

    > Agreed, but there's always the danger the +array method, which might
    > actually be implemented in NSArray.m, will not properly initialize the
    > more specific NSMutableArray object.
    >
    > Of course, in this specific case that's the case, but it might be the
    > case with other class hierarchies.
    >
    > But, nonetheless I'm troubled that nobody in this thread has
    > acknowledged that yet :-o

    Because acknowledging that some people will release buggy frameworks goes without saying. I'm not aware of any Apple classes that have that bug.

    — F
  • On Thu, Apr 8, 2010 at 10:21 AM, Patrick M. Rutkowski
    <rutski89...> wrote:
    > Agreed, but there's always the danger the +array method, which might
    > actually be implemented in NSArray.m, will not properly initialize the
    > more specific NSMutableArray object.

    A correct subclass MUST ensure that things are correctly initialized
    otherwise document that it doesn't do that.

    > Of course, in this specific case that's the case, but it might be the
    > case with other class hierarchies.

    It would be a poorly implemented if that was the case and either
    should be reworked or clearly documented.

    > But, nonetheless I'm troubled that nobody in this thread has acknowledged that yet :-o

    Not acknowledged what? You can always write buggy code that doesn't
    conform to expectations / conventions... the goal is to not do that.

    -Shawn
  • On Apr 8, 2010, at 10:21 AM, Patrick M. Rutkowski wrote:

    > Agreed, but there's always the danger the +array method, which might
    > actually be implemented in NSArray.m, will not properly initialize the
    > more specific NSMutableArray object.
    >
    > Of course, in this specific case that's the case, but it might be the
    > case with other class hierarchies.
    >
    > But, nonetheless I'm troubled that nobody in this thread has
    > acknowledged that yet :-o

    Because, in practice, that doesn't generally happen.

    Across the system supplied frameworks, classes generally have designated initializers and those initializers are inherited properly.  The convenience creation methods -- factory methods, if you will -- are dead simple stupid, generally doing the equivalent of '[[[self alloc] init*] autorelease]' where the init part calls the designated initializer.

    If a subclass needs a more specific initializer, the inherited, simpler, initializer from the superclass is typically overridden to barf an error or call the more specific with a default argument.

    Thus, the risk is largely -- there are probably an exception or two and, if you know of one, file a bug -- confined to the code you write.  Generally, class hierarchies in Objective-C tend to be relatively shallow and relatively well factored (if you are doing it right, anyway).    When there is inheritance, the most effective use is in maintaining consistency in interface across super and subclasses, including the designated initializers.

    So, again, in your own code the risk should be relatively minor in a clean design.

    Now, of course, none of us are perfect and just about all of us have put together a shoddily architected, way too deep, class hierarchy now and again.  Even when slinging crap code, there is no reason why it can't be defensive crap code, too!

    b.bum
  • On Apr 8, 2010, at 12:29 PM, Bill Bumgarner wrote:

    >
    > On Apr 8, 2010, at 10:21 AM, Patrick M. Rutkowski wrote:
    >
    >> Agreed, but there's always the danger the +array method, which might
    >> actually be implemented in NSArray.m, will not properly initialize the
    >> more specific NSMutableArray object.
    >>
    >> Of course, in this specific case that's the case, but it might be the
    >> case with other class hierarchies.
    >>
    >> But, nonetheless I'm troubled that nobody in this thread has
    >> acknowledged that yet :-o
    >
    > Because, in practice, that doesn't generally happen.
    >
    > Across the system supplied frameworks, classes generally have designated initializers and those initializers are inherited properly.  The convenience creation methods -- factory methods, if you will -- are dead simple stupid, generally doing the equivalent of '[[[self alloc] init*] autorelease]' where the init part calls the designated initializer.

    There is a problem with "things that look like convenience creation methods but aren't" - most notably +[NSParagraphStyle defaultParagraphStyle].  You might expect:

    NSMutableParagraphStyle *ps = [NSMutableParagraphStyle defaultParagraphStyle];
    [ps setAlignment: NSCenterTextAlignement];

    to work.  It doesn't (since ps is actually an immutable NSParagraphStyle).

    The major clue that is isn't a convenience creation method being found in the declaration:

    - (NSParagraphStyle *) defaultParagraphStyle;

    instead of:

    - (id) defaultParagraphStyle;

    Glenn Andreas                      <gandreas...>
    The most merciful thing in the world ... is the inability of the human mind to correlate all its contents - HPL
  • On Thu, Apr 8, 2010 at 1:21 PM, Patrick M. Rutkowski <rutski89...> wrote:
    > Agreed, but there's always the danger the +array method, which might
    > actually be implemented in NSArray.m, will not properly initialize the
    > more specific NSMutableArray object.
    >
    > Of course, in this specific case that's the case, but it might be the
    > case with other class hierarchies.
    >
    > But, nonetheless I'm troubled that nobody in this thread has
    > acknowledged that yet :-o

    Take a look at the declaration for this method:

    + (id)array;

    This is subtle... but it actually tells you everything you need to
    know for this question.

    The key is the "id" return type. Although at the language level this
    just means that it returns some kind of object, it has a deeper
    meaning when it comes to Cocoa conventions. More specifically, an "id"
    type on a factory method like this means that the method will return
    an instance of the class that the message is sent to, even if it's a
    subclass. (It could return an instance of a subclass of that class,
    but that's perfectly legal.) The "id' means that subclasses will work
    correctly, and that the implementation uses [self alloc].

    Virtually all factory methods are declared like this, and thus that's
    how they work.

    As a counterexample, look at +[NSParagraphStyle defaultParagraphStyle]:

    + (NSParagraphStyle *)defaultParagraphStyle;

    It's not declared to return 'id'. This means that
    [NSMutableParagraphStyle defaultParagraphStyle] is *not* guaranteed to
    return an instance of NSMutableParagraphStyle. It could, but you
    shouldn't count on it. You have to assume that the object you get is
    always a straight NSParagraphStyle, and code accordingly. (In this
    particular case, you'd make a mutable copy of the returned object,
    then use that.)

    As a bonus, this convention means that the compiler will yell at you
    if you try to write code like:

    NSMutableParagraphStyle *style = [NSMutableParagraphStyle
    defaultParagraphStyle];

    Of course you can't count on warnings to keep you safe all the time,
    but it helps.

    So check for the 'id' return value, and if it's there, you can code in
    confidence.

    Mike
  • Wow! Good stuff Michael :-)

    I can't believe I never noticed that.

    On Thu, Apr 8, 2010 at 3:07 PM, Michael Ash <michael.ash...> wrote:
    > On Thu, Apr 8, 2010 at 1:21 PM, Patrick M. Rutkowski <rutski89...> wrote:
    >> Agreed, but there's always the danger the +array method, which might
    >> actually be implemented in NSArray.m, will not properly initialize the
    >> more specific NSMutableArray object.
    >>
    >> Of course, in this specific case that's the case, but it might be the
    >> case with other class hierarchies.
    >>
    >> But, nonetheless I'm troubled that nobody in this thread has
    >> acknowledged that yet :-o
    >
    > Take a look at the declaration for this method:
    >
    > + (id)array;
    >
    > This is subtle... but it actually tells you everything you need to
    > know for this question.
    >
    > The key is the "id" return type. Although at the language level this
    > just means that it returns some kind of object, it has a deeper
    > meaning when it comes to Cocoa conventions. More specifically, an "id"
    > type on a factory method like this means that the method will return
    > an instance of the class that the message is sent to, even if it's a
    > subclass. (It could return an instance of a subclass of that class,
    > but that's perfectly legal.) The "id' means that subclasses will work
    > correctly, and that the implementation uses [self alloc].
    >
    > Virtually all factory methods are declared like this, and thus that's
    > how they work.
    >
    > As a counterexample, look at +[NSParagraphStyle defaultParagraphStyle]:
    >
    > + (NSParagraphStyle *)defaultParagraphStyle;
    >
    > It's not declared to return 'id'. This means that
    > [NSMutableParagraphStyle defaultParagraphStyle] is *not* guaranteed to
    > return an instance of NSMutableParagraphStyle. It could, but you
    > shouldn't count on it. You have to assume that the object you get is
    > always a straight NSParagraphStyle, and code accordingly. (In this
    > particular case, you'd make a mutable copy of the returned object,
    > then use that.)
    >
    > As a bonus, this convention means that the compiler will yell at you
    > if you try to write code like:
    >
    > NSMutableParagraphStyle *style = [NSMutableParagraphStyle
    > defaultParagraphStyle];
    >
    > Of course you can't count on warnings to keep you safe all the time,
    > but it helps.
    >
    > So check for the 'id' return value, and if it's there, you can code in
    > confidence.
    >
    > Mike
    >
previous month april 2010 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    
Go to today