Mutable classes and class clusters

  • Hello, all.

    After some checking through the archives, I wasn't able to find the
    answers I wanted (*grin*), so I'm checking here now.

    My questions:
    1) What benefits do separate immutable and mutable classes provide? I'm
    developing a framework, and I'm wondering whether I should separate the
    mutable aspects of some of my classes into a mutable subclass.
    It occurs to me that the rationale behind this decision might have been
    the fact that NSArray et al are class clusters. Is this the case?

    2) One of the classes I'm implementing in my framework is about to be
    redesigned as a class cluster, with a single public class (unless I find
    that separating it into mutable and immutable would be worthwhile, of
    course). So, to make a class cluster, is all that is involved changing my
    class' -(id)init method so that it returns an instance of a private
    subclass? Should I also have said private subclasses report that they are
    actually members of the superclass when queried with things like
    -isMemberOfClass, -class, and +class?

    Thanks very much,

    -- Rob

    If there's anything more important than my ego around, I want it caught
    and shot now. - Zaphod
  • On Saturday, September 15, 2001, at 09:48 PM, Rob Rix wrote:

    > 1) What benefits do separate immutable and mutable classes provide? I'm
    > developing a framework, and I'm wondering whether I should separate the
    > mutable aspects of some of my classes into a mutable subclass.
    > It occurs to me that the rationale behind this decision might have been
    > the fact that NSArray et al are class clusters. Is this the case?

    The point is that it allows you to tell the user of a class that "I will
    not modify this (argument) object", or "You may not modify this object"
    and so forth.

    Consider something like;
    - (NSArray*)windows;
    versus
    - (NSMutableArray*)windows;

    In the first, you're handed an array which you're not allowed to change.
    In the second, the type is telling you that you can change it.

    If you find yourself in a situation where you often make copies of an
    object before returning it, or passing it as an argument, then a
    mutable/immutable class is useful.

    > 2) One of the classes I'm implementing in my framework is about to be
    > redesigned as a class cluster, with a single public class (unless I
    > find that separating it into mutable and immutable would be worthwhile,
    > of course). So, to make a class cluster, is all that is involved
    > changing my class' -(id)init method so that it returns an instance of a
    > private subclass?

    Essentially. Don't forget to collect any garbage in the init method,
    though.

    You may also want to handle serialization; otherwise you can become
    locked in with a certain implementation. "replacementObjectForCoder:"
    should be helpful, there.

    > Should I also have said private subclasses report that they are
    > actually members of the superclass when queried with things like
    > -isMemberOfClass, -class, and +class?

    I can't see any good reasons for doing that.

    Regards,
    John Hornkvist
    --
    ToastedMarshmallow, the perfect Cocoa companion
    http://www.toastedmarshmallow.com
  • > The point is that it allows you to tell the user of a class that "I will
    > not modify this (argument) object", or "You may not modify this object"
    > and so forth.
    >
    > Consider something like;
    > - (NSArray*)windows;
    > versus
    > - (NSMutableArray*)windows;
    >
    > In the first, you're handed an array which you're not allowed to change.
    > In the second, the type is telling you that you can change it.
    >
    > If you find yourself in a situation where you often make copies of an
    > object before returning it, or passing it as an argument, then a mutable/
    > immutable class is useful.

    Okay, this would also solve another of my problems: the problem of locking
    a spline so that it won't be modified.
    Makes sense...

    > Essentially. Don't forget to collect any garbage in the init method,
    > though.

    Such as removing the instance of the public class that was just allocated?

    > You may also want to handle serialization; otherwise you can become
    > locked in with a certain implementation. "replacementObjectForCoder:"
    > should be helpful, there.

    Ah, yes. This will be useful once I finally get around to having
    everything adopt the coding protocol :)

    > I can't see any good reasons for doing that.

    Okay, excellent.

    Thanks very much, John.

    -- Rob

    For this is summer--we spin slowly on the edge of song. - Kira Byers
  • On Saturday, September 15, 2001, at 03:48 PM, Rob Rix wrote:

    > Hello, all.
    >
    > After some checking through the archives, I wasn't able to find the
    > answers I wanted (*grin*), so I'm checking here now.
    >
    > My questions:
    > 1) What benefits do separate immutable and mutable classes provide? I'm
    > developing a framework, and I'm wondering whether I should separate the
    > mutable aspects of some of my classes into a mutable subclass.
    > It occurs to me that the rationale behind this decision might have been
    > the fact that NSArray et al are class clusters. Is this the case?

    John Hvrnkvist gave a good point, but another reason is performance.
    When you send a copy message to a mutable object, it has to actually
    allocate another object, but an immutable object can simply retain
    itself and return self (and you can test yourself that the pointer you
    get back from a copy message sent to an immutable string is the same),
    which is faster and uses less memory.  An NSMutableArray is likely to
    keep some extra space around at the end of the array for adding more
    object on to it, but an immutable NSArray can use just enough space to
    hold all of its objects, saving on memory.  Likewise, the docs say that
    NSCharacterSet is much faster than NSMutableCharacterSet (anyone know
    why?)

    If you know that your object won't change, you can take advantage of a
    lot of powerful techniques for making it faster.  For example, you can
    often forgo locks on accesses to immutable objects from different
    threads.  Or you might want to invest in a perfect hash for
    constant-time searching of the object.

    So you might want to go to mutable and immutable types if you expect
    your classes will be used in performance-sensitive contexts and you can
    realize a speed increase from doing so.

    >
    > 2) One of the classes I'm implementing in my framework is about to be
    > redesigned as a class cluster, with a single public class (unless I
    > find that separating it into mutable and immutable would be worthwhile,
    > of course). So, to make a class cluster, is all that is involved
    > changing my class' -(id)init method so that it returns an instance of a
    > private subclass? Should I also have said private subclasses report
    > that they are actually members of the superclass when queried with
    > things like -isMemberOfClass, -class, and +class?
    >
    > Thanks very much,

    There's typically more to it than that.  You probably will want to
    create a sort of proxy member of your class cluster, with no instance
    variables, and override alloc to return an instance of that.  Then
    implement your various init methods in that proxy class, and in each of
    them destroy the instance of the proxy class method (aka self) and
    allocate and initialize the right member of your class cluster.

    As far as I can tell, this is what Apple does.  For example, consider
    the following code:

            NSString* string=[NSString alloc];
            NSLog(@"Pre-init address %p Description: %@", string, [string
    class]);
            string=[string initWithCString:"Hello World"];
            NSLog(@"Post-init address %p Description: %@", string, [string
    class]);

    On my machine, this prints

        Pre-init address 0xe5b30 Description: NSPlaceholderString
        Post-init address 0xe5a8d0 Description: NSCFString

    Notice two things: the existence of a proxy class "NSPlaceholderString"
    and the fact that the initialized string has a different address than
    the uninitialized string.

    Also notice that the class message reports the actual class of the
    object instead of claiming to be members of the superclass, so I
    wouldn't override those methods if I were you.  Clueful Cocoa
    programmers know to use isKindOfClass: rather than isMemberOfClass: when
    potentially dealing with class clusters anyways.

    Hope this helps.

    -Peter
  • On Saturday, September 15, 2001, at 12:48  PM, Rob Rix wrote:
    > 2) One of the classes I'm implementing in my framework is about to be
    > redesigned as a class cluster, with a single public class (unless I
    > find that separating it into mutable and immutable would be worthwhile,
    > of course). So, to make a class cluster, is all that is involved
    > changing my class' -(id)init method so that it returns an instance of a
    > private subclass?

    Or instead of allocating an object only to have it deallocated in -init,
    override +allocWithZone: to allocate an instance of the appropriate
    concrete class.

    + (id)allocWithZone:(NSZone *)zone {
    if ([MyAbstractClass self] == self)
      return NSAllocateObject([MyConcreteClass self], 0, zone);
    return [super allocWithZone:zone];
    }

    Then the -init method will go right to an instance of the concrete
    class.  This works well when for any particular abstract class you know
    which concrete class to use (ie, there is a one-to-one correspondence).
    If you don't know which class you'll need until the init method is
    called, or otherwise don't have enough information at +allocWithZone:
    time to allocate the real object, then going through a placeholder
    singleton object (returning that from the +allocWithZone:) is an
    efficient way to go.  Peter Ammon <pa44...> talked about this
    in another email.

    Chris Kane
    Cocoa Frameworks, Apple
previous month september 2001 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