[Biococoa-dev] Mutable classes implementation
charles.parnot at gmail.com
Mon Jul 11 02:24:21 EDT 2005
On Jul 10, 2005, at 6:18 PM, John Timmer wrote:
> ...<snip>... I was thinking
> about this one the way home, and I like the idea of two different
> initializers, say initMutableSequence and initSequence. We could
> have our
> internal data ivar be untyped, and simply make it mutable data or
> data in the init method, and set an isMutable BOOL ivar. All the
> work gets
> done in the init method, and we don't have to add any new classes.
> Does this make sense, or is this dangerous in some other way?
> PS - incidentally, how are we handling Xcode 2.1 and the .xcodeproj
I completely agree with the internals. This is also how I would do
it, and I think this is how NSArray was implemented. However, I would
handle the public interface differently and model it after the Cocoa
* the init method can be the same; what determines the mutability is
the calling class; polymorphism is good!
* you need a different class to have compiler checking, and warn you
when you call a mutability method on an immutable class... well, this
the same argument as the -complement method for BCDNASequence and
I was interrupted while writing this email, and I was thinking about
it more while doing other stuff... Now I am back with some
implementation ideas. The problem with having separate mutable
classes is how to not duplicate code when you have two types of
objects, and you can't have multiple inheritance (mutability and
Here is how I would implement it
* All the mutability methods are implemented in the superclass
BCSequence (assuming we rename BCSequenceAbstract to BCSequence,
which we should probably do, I suppose), like '-appendSequence:', '-
removeSequenceAtRange:',... Maybe some of the mutability sequence
need to be implemented at the level of the subclasses, for instance
if we want to implement a '-digestWithKlenow' (this is just an
example). This is fine, the implementation can be in BCDNASequence.
However, all of these methods should start by checking the value of
the isMutable ivar, and throw an exception if the object is not
mutable. Also, these methods should not be declared in the headers of
BCSequence, BCDNASequence,... because they are illegal for these
classes. At this point, these methods are useless. They are not
public, and if you call them, your program crash!
* Now, of course, how do we get mutable objects?? First the public
side of it.
- We declare 5 more classes: BCMutableSequence (inherits from
BCSequence) and then BCMutableProteinSequence,
BCMutableNucleotideSequence, BCMutableDNASequence and
BCMutableRNASequence (all 4 inheriting from BCMutableSequence)
- The header for BCMutableSequence declares the method '-
- The header for BCMutableDNASequence declares '-complement', '-
digestWithKlenow',... and the same thin for the other subclasses if
any specific mutability methods exist
- So, now, the user and the compiler think they have some mutable
classes and they know about the methods that can be called
- The methods declared in the superclass, like '-initWithString:'
or '-reverse', also appear valid to the user and the compiler and can
officially be called for mutable sequences; in particular, the '-
initWithString:' is supposed to return a mutable instance
- All methods specific for some of the sequence types, like '-
complement' and 'hydrophobicity', are also declared in the headers of
the mutable classes, so the user and the compiler can officically use
* So far, it looks like we have to write all these declared methods
again for all these classes. But what happens internally at
runtime??? Well, you should know me now. All the mutable classes are
in fact... placeholder classes!!
- The first important trick is: the designated initializer for the
root class BCSequence has to include a 'isMutable:(BOOL)flag'
argument (the method should probably be private, or at least not
documented). This way, the init methods in the placeholder class can
call it with isMutable:YES
- Then the init methods are the only methods actually implemented in
the BCMutableXXX classes, and they return instances of the
BCXXXSequence. Of course, these instances have their isMutable flag
set to YES, which is done by calling the designated initializer with
mutable:YES. After being initialized, at runtime, these objects then
behave as mutable, and can run the mutability methods without
throwing exceptions. And then all the methods only need to be
implemented in the BCXXXSequence subclasses, and not in the
BCMutableXXX classes, which are just alive between alloc and init.
This is a generalized version of the NSArray/NSMutableArray Apple's
design. The init methods from both class always return instances of
NSCFArray, with different values for the isMutable flags.
It seems to be popular now to attach some OmniGraffle document, so
here it is...
It was too big for the limit on the mailing list, so I put it on the
OK, bed time... have a nice week...
Help science move fast forward:
charles.parnot at gmail.com
More information about the Biococoa-dev