title: Subclassing a set of inter-dependent classes in Objective-C and ensuring type-safety
body: <p>I've implemented a basic <strong>graph class</strong> (not as in "plotting" but as in "network"!), that's to be used for <strong>basic graph theoretical tasks</strong>. <em>(see summarised header file snippets below)</em></p>
  
  <p>In addition to the <strong>generic graph functionality</strong> it also implements <strong>functionality for node positioning in 3D space</strong>. <strong>And this extended 3D functionality I'd like to isolate into a subclass</strong>, resulting in:</p>
  
  <ul>
  <li>light-weight generic classes <code>(MyGenericGraph,
  MyGenericGraphNode, MyGenericGraphEdge)</code></li>
  <li>heavier-weight specialized subclasses
  <code>(My3DGraph, My3DGraphNode,
  My3DGraphEdge)</code></li>
  </ul>
  
  <p>So far so good, in theory, that is.</p>
  
  <h2>Problem:</h2>
  
  <p>I'd have to ensure (and preferably at compile time) that one cannot add generic <code>MyGenericGraphNodes</code> to the spezialized <code>My3DGraph</code>, as it highly depends on the added 3D logic inside <code>My3DGraphNode</code>. (While the generic <code>MyGenericGraph</code> would simply not care.)</p>
  
  <p>The core issue is as simple as this: I cannot override these methods from MyGenericGraph:</p>
  
  <pre><code>- (void)addNode:(MyGenericGraphNode *)aNode;
  - (void)removeNode:(MyGenericGraphNode *)aNode;
  </code></pre>
  
  <p>with these methods in my subclass My3DGraph:</p>
  
  <pre><code>- (void)addNode:(My3DGraphNode *)aNode;
  - (void)removeNode:(My3DGraphNode *)aNode;
  </code></pre>
  
  <p>I've so far come up with three possible solutions but before going for any of them I'd like to hear some opinions on them. (and hopefully spare me some unforeseen troubles on my way)</p>
  
  <p>I'm wondering if there's <strong>another and superior solution or design pattern</strong> to this that I'm missing? <strong>Or if not: which of my solutions would you go for?</strong><br>
  I'd love to hear your opinion on this.</p>
  
  <h2>Possible solution 1</h2>
  
  <ul>
  <li><strong>Adding an abstract class</strong> <code>MyAbstractGraph</code> that would basically be <strong>identical to the generic parts of my current implementation</strong> of <code>MyGenericGraph</code> (see below), but would <strong>lack any node-addition/removal methods</strong>. <code>MyGenericGraph</code> <strong>and</strong> <code>My3DGraph</code> <strong>would then simply be subclasses of</strong> <code>MyAbstractGraph</code>. And while <code>MyGenericGraph</code> would only implement the lacking node-addition/removal methods, <code>My3DGraph</code> would further more implement all 3D space functionality. Both requiring their respective node class types. (same for <code>MyGenericGraphNode</code> and <code>MyGenericGraphEdge</code> and their 3D counterparts)</li>
  </ul>
  
  <p><strong>Problems with this solution:</strong> It would <strong>add a significant amount of complexity</strong> to an otherwise <strong>rather simple problem</strong>.<br>
  Further more as <code>My3DGraph</code> should be able to deal with <code>My3DGraphNodes</code> AND <code>MyGenericGraphNodes</code>, I'd have to implement <code>MyGenericGraph</code>'s method as:</p>
  
  <pre><code>- (void)addNode:(MyAbstractGraphNode *)aNode;`
  </code></pre>
  
  <p>but <code>My3DGraph</code>'s method as:</p>
  
  <pre><code>- (void)addNode:(My3DGraphNode *)aNode;
  </code></pre>
  
  <p>as well, as otherwise my generic graph it wouldn't accept 3d nodes. This would expose the abstract class unnecessarily though.</p>
  
  <h2>Possible solution 2</h2>
  
  <p><strong>True and simple subclasses + moving</strong> <code>MyGenericGraphNode/My3DGraphNode</code> <strong>allocation right into</strong> <code>MyGenericGraph/My3DGraph</code>, to get something like: <code>- (MyGenericGraphNode *)newNode;</code>, which would <strong>allocate and return a node</strong> of correct type <strong>and add it to the graph</strong> right away. One would then <strong>get rid of</strong> <code>- (void)addNode:(MyGenericGraphNode *)aNode;</code> entirely, <strong>leaving no chance to add nodes than from within the Graph itself</strong> (hence assuring proper class membership).</p>
  
  <p><strong>Problems with this solution:</strong> While it would not add any noteworthy complexity to the classes, it would on the other hand basically get me into the same predicament again, as soon as I—let's say—wanted to add functionality to my <code>My3DGraph</code> for moving a node from one graph to another. And imho a class should be able to deal with an object no matter who created it and why.</p>
  
  <h2>Possible solution 3</h2>
  
  <p><strong>True and simple subclasses + adding specialized method for 3D nodes and disabling generic method</strong>, like so:</p>
  
  <pre><code>- (void)addNode:(MyGenericGraphNode *)aNode {
      [self doesNotRecognizeSelector:_cmd];
  }
  
  - (void)add3DNode:(My3DGraphNode *)aNode {
      //bla
  }
  </code></pre>
  
  <p><strong>Problems with this solution:</strong> The generic <code>[a3DGraph addNode:aNode]</code> method would still show up in Xcode's auto-complete, pass silently on compile, but unexpectedly throw exception on run. Frequent headaches foreseen.</p>
  
  <h2>Possible solution 4</h2>
  
  <p><strong>True and simple subclasses for my graph and just the generic classes for node and edge, but with an additional ivar pointer <code>My3DUnit *dimensionalUnit:</code> in node class (defaulting to nil for MyGraph) that implements all the logic and properties and provides 3D functionality to the node class.</strong> <code>My3DUnit</code> can simply be silently created (with position (0,0,0) e.g.) and attached to generic nodes in case they get added to a 3d graph, and hence made compatible. Vice versa if a node with a <code>DL3DUnit</code>gets added to a generic graph it simply keeps it attached and adds the node.</p>
  
  <h2>Header Files</h2>
  
  <p>Here are the (shortened) headers of my classes:</p>
  
  <pre><code>@interface MyGraph : NSObject {
      // properties:
      NSMutableSet *nodes;
      //...
  
      //extended 3D properties:
  double gravityStrength;
      //...
  }
  // functionality:
  - (void)addNode:(MyGraphNode *)aNode;
  - (void)removeNode:(MyGraphNode *)aNode;
  //...
  
  //extended 3D functionality:
  - (double)kineticEnergy;
  //...
  
  @end
  
  @interface MyGraphNode : NSObject { 
      // properties:
      MyGraph *graph;
      NSMutableSet *edges;
      //...
  
      //extended 3D properties:
      My3DVector position;
      //...
  }
  // properties:
  @property (nonatomic, readonly) MyGraph *graph;
  @property (nonatomic, readonly) NSSet *edges;
  @property (nonatomic, readonly) NSSet *neighbors;
  @property (nonatomic, readonly) NSUInteger degree;
  //...
  
  //extended 3D properties
  @property (nonatomic, assign) My3DVector position;
  //...
  
  // functionality:
  - (void)attachToGraph:(MyGraph *)aGraph;
  - (void)detachFromGraph;
  - (void)addNeighbor:(MyGraphNode *)aNode;
  - (void)removeNeighbor:(MyGraphNode *)aNode;
  - (BOOL)hasNeighbor:(MyGraphNode *)aNode;
  - (NSSet *)neighbors;
  - (NSUInteger)degree;
  //...
  
  //extended 3D functionality:
  - (double)distanceToNode:(DLGraphNode *)aNode;
  //...
  
  @end
  
  @interface MyGraphEdge : NSObject {
      // properties:
      MyGraphNode *predecessor;
      MyGraphNode *successor;
      //...
  }
  
  // properties:
  @property (nonatomic, readonly) MyGraphNode *predecessor;
  @property (nonatomic, readonly) MyGraphNode *successor;
  //...
  
  // functionality:
  - (id)initWithPredecessorNode:(MyGraphNode *)predecessorNode successorNode:(MyGraphNode *)successorNode;
  + (MyGraphEdge *)edgeWithPredecessorNode:(MyGraphNode *)predecessorNode successorNode:(MyGraphNode *)successorNode;
  - (BOOL)hasNeighbor:(MyGraphNode *)aNode;
  - (BOOL)hasSuccessor:(MyGraphNode *)aNode;
  - (BOOL)hasPredecessor:(MyGraphNode *)aNode;
  
  @end
  </code></pre>
  
  <p><em>This is basically how my graph is implemented right now. There's obviously quite a bunch more to it, but you should get the idea.</em></p>
  
  <p>(As you might have noticed MyGenericGraphEdge currently implements no 3D space functionality, but it might in the future, like computing its center point, e.g., hence I've included it here.)</p>
  
  <p>[Edit: Added solution 4 inspired by ughoavgfhw; fixed a mistake in solution 1, sorry for that :(]</p>