{"id":2102,"date":"2012-11-11T20:04:22","date_gmt":"2012-11-11T19:04:22","guid":{"rendered":"http:\/\/t-machine.org\/?p=2102"},"modified":"2012-11-11T21:38:14","modified_gmt":"2012-11-11T20:38:14","slug":"objectivec-how-to-make-an-abstract-class-forbid-the-init-method","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2012\/11\/11\/objectivec-how-to-make-an-abstract-class-forbid-the-init-method\/","title":{"rendered":"ObjectiveC: how to make an abstract class \/ forbid the &#8220;init&#8221; method"},"content":{"rendered":"<h3>Abstract classes: saving programmers from each other<\/h3>\n<p>For trivial apps, no-one cares. But most libraries take huge advantage of the concept of &#8220;subclassing&#8221;, and programmers using those libraries need to make intelligent choices about &#8220;which subclass do I use?&#8221;.<\/p>\n<p>Thanks to auto-complete, or &#8220;because it sounded what I needed at that moment in time&#8221; &#8211; or simply &#8220;because I was tired&#8221; &#8211; your base class gets instantiated when it shouldn&#8217;t have been. And strange bugs come from it, wasting everyone&#8217;s time. You might argue &#8220;not MY time&#8221;, but I&#8217;m a strong believer in writing code that EITHER does the obvious OR protects the people using it &#8211; my code doesn&#8217;t crash, it checks for obvious mistakes (e.g. checks that a file exists before loading it!), etc.<\/p>\n<p>In the long run, that frequently comes back to help you: when YOU then re-use your own code, and make a dumb mistake because it&#8217;s been a long time and you&#8217;d forgotten how to use it.<\/p>\n<p>In some languages, you can create &#8220;abstract base classes&#8221; that allow other classes to share type, but cannot be used on their own. This makes it obvious to other programmers that they should look for subclasses and pick one &#8211; instead of trying to use the superclass.<\/p>\n<p>Unfortunately, ObjectiveC has no support for &#8220;abstract classes&#8221;.<\/p>\n<p>&#8230;or does it?<\/p>\n<h3>What&#8217;s an abstract class?<\/h3>\n<p>An abstract class is one that cannot be instantiated. To achieve that in Objective-C, all you have to do is:<\/p>\n<pre lang=\"objc\">\r\n@implementation DontAllowInit\r\n\r\n- (id)init\r\n{\r\n    NSAssert(false, @\"You cannot init this class directly. Instead, use a \r\nsubclass e.g. AcceptableSubclass\");\r\n\r\n    \/\/ NB: I prefer to use NSAssert because this is aimed at programmers, and \r\n    \/\/     ObjC programmers should generally be using assertions during dev!\r\n \r\n    \/\/ You could instead use more fancy approaches, like raising an NSException\r\n    \/\/     - but Apple\/Cocoa are very anti-exception, and don't support them well.\r\n\r\n    return nil;\r\n}\r\n@end\r\n<\/pre>\n<p>&#8230;but this causes a problem. Because as soon as someone creates a subclass, they&#8217;ll find their code crashes:<\/p>\n<pre lang=\"objc\">\r\n@interface SubClass : DontAllowInit\r\n@end\r\n\r\n@implementation SubClass\r\n\r\n- (id)init\r\n{\r\n    self = [super init]; \/\/ CRASH!\r\n    if( self != nil )\r\n    {\r\n        \/\/ all the normal setup code\r\n    }\r\n    return self;\r\n}\r\n@end\r\n<\/pre>\n<p>You can workaround this by writing documentation that says:<\/p>\n<blockquote><p>\n\/*<br \/>\nThis class can&#8217;t be instantiated, because I wanted an Abstract Class, but Objective-C was too primitive to allow it.<\/p>\n<p>So, um, please don&#8217;t call [super init]. Instead call &#8230; ah .. [super secretInit] which does the same thing, but which other people won&#8217;t realise exists!<br \/>\n*\/\n<\/p><\/blockquote>\n<p>There&#8217;s an obvious problem there &#8230; the super-secret-init is easy to call anyway, and BOOM your library. It might seem obvious to you that no-one would call that method without understanding it, but this is the way of the world.<\/p>\n<h3>Selective Denial: what am I?<\/h3>\n<p>The solution is to think about what happens when you instantiate a subclass. The key thing here is that when you call:<\/p>\n<pre lang=\"objc\">\r\nSuper* s = [[Super alloc] init];\r\n<\/pre>\n<p>it&#8217;s NOT the same as when you call:<\/p>\n<pre lang=\"objc\">\r\nSub* s = [[Sub alloc] init];\r\n<\/pre>\n<p>&#8230;in the first case, the thing that gets sent &#8220;init&#8221; is an instance of &#8220;Super&#8221;, whereas in the second case it&#8217;s an instance of &#8220;Sub&#8221;.<\/p>\n<p>That might not sound interesting, but when Sub executes the first (standards-compliant) line of its init method:<\/p>\n<p>The key thing here is that when you call:<\/p>\n<pre lang=\"objc\">\r\n-(id) init\r\n{\r\n     self = [super init];\r\n<\/pre>\n<p>&#8230;then the code in Super.m is *not* being run on an object of type &#8220;Super&#8221;, but rather an object of type &#8220;Sub&#8221;.<\/p>\n<p>And so we have a solution:<\/p>\n<pre lang=\"objc\">\r\n@implementation DontAllowInit\r\n- (id)init\r\n{\r\n\tif( [self class] == [DontAllowInit class])\r\n\t{\r\n\t\tNSAssert(false, @\"You cannot init this class directly. Instead, use a subclass e.g. MyPreferredSubclass\");\r\n\t\t\r\n\t\treturn nil;\r\n\t}\r\n\telse\r\n\t\treturn [super init];\r\n}\r\n<\/pre>\n<h3>Does it really matter?<\/h3>\n<p>When writing code, you have lots to think about. In my years of experience, two of the most important questions are:<\/p>\n<ol>\n<li>Does it do what it says \/ work as intended?\n<li>Can someone else use (and modify) the code later, when you&#8217;re not there &#8230; correctly?\n<\/ol>\n<p>Documentation goes a long way to solving both those issues. However &#8230; docs take a long time to write, and more importantly:<\/p>\n<blockquote><p>\nOther people frequently don&#8217;t read the documentation\n<\/p><\/blockquote>\n<p>More importantly:<\/p>\n<blockquote><p>\nIf you are a great programmer, other programmers SHOULD NOT NEED TO read the code documentation any more than they expected to\n<\/p><\/blockquote>\n<p>&#8220;Expected to&#8221; is critical here. If your codebase is 1 million lines long, then a programmer would be insane to think they could just &#8220;dive in&#8221; and start writing \/ modifying it &#8211; the thing is fantastically complex. But if it&#8217;s clear and simple, then often they should expect to read the &#8220;core&#8221; documentation, and be able to work the rest out as they go, from reading your class and method names.<\/p>\n<p>Abstract classes enable you &#8211; with very little effort &#8211; to use complex chains of OOP subclassing <em>without endangering the programmers who come after you<\/em>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Abstract classes: saving programmers from each other For trivial apps, no-one cares. But most libraries take huge advantage of the concept of &#8220;subclassing&#8221;, and programmers using those libraries need to make intelligent choices about &#8220;which subclass do I use?&#8221;. Thanks to auto-complete, or &#8220;because it sounded what I needed at that moment in time&#8221; &#8211; [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/2102"}],"collection":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/comments?post=2102"}],"version-history":[{"count":0,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/2102\/revisions"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=2102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=2102"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=2102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}