{"id":119,"date":"2008-08-31T20:00:29","date_gmt":"2008-09-01T01:00:29","guid":{"rendered":"http:\/\/vgable.com\/blog\/2008\/08\/31\/better-list-termination\/"},"modified":"2008-08-31T20:00:30","modified_gmt":"2008-09-01T01:00:30","slug":"better-list-termination","status":"publish","type":"post","link":"https:\/\/vgable.com\/blog\/2008\/08\/31\/better-list-termination\/","title":{"rendered":"Better List Termination"},"content":{"rendered":"<p>As I&#8217;ve <a href=\"http:\/\/vgable.com\/blog\/2008\/07\/17\/null-terminated-argument-lists\/\">written before<\/a>, using <code>nil<\/code> to terminate a variable-length list (eg <code>[NSArray arrayWithObject:foo,bar,nil]<\/code>) is a bad choice because of how easy it is to get a <code>nil<\/code> value in Objective-C without knowing it.  (Unlike, say C++, <a href=\"http:\/\/vincentgable.com\/blog\/2008\/05\/31\/messages-to-nowhere\/\">doing stuff with <code>nil<\/code> won&#8217;t cause an exception<\/a>, leading to some subtle bugs).  Well, here is a solution.<\/p>\n<p><strong>A Better Sentinel<\/strong><\/p>\n<p><code>#define END_OF_LIST ((id) -1)<\/code><br \/> is my current choice of a good sentinel-value.  It is an invalid pointer, so unlike <code>nil<\/code>, you should never get it back from some library.  <strong>Sending it any message will fail fast, and recognizably<\/strong> (you will see <code>0xFF...FF<\/code> as an illegal address somewhere in the back-trace).<\/p>\n<p><strong>Example:<\/strong><\/p>\n<p>\n<code><br \/>\nid aNilObject = nil;<br \/>\nNSArray *standard = [NSArray arrayWithObjects:@\"1\", @\"2\", aNilObject, @\"4\", nil];<br \/>\n<a href=\"http:\/\/vgable.com\/blog\/2008\/08\/05\/simpler-logging-2\/\">LOG_ID<\/a>(standard);<br \/>\nNSArray *better = [NSArray arrayWithSentinelTerminatedObjects:@\"1\", @\"2\", aNilObject, @\"4\", END_OF_LIST];<br \/>\n<a href=\"http:\/\/vgable.com\/blog\/2008\/08\/05\/simpler-logging-2\/\">LOG_ID<\/a>(better);<br \/>\n<\/code><br \/>\n<br \/>\n<em>standard = (<br \/>\n&nbsp;&nbsp;&nbsp;1,<br \/>\n&nbsp;&nbsp;&nbsp;2<br \/>\n)<br \/>\nbetter = (<br \/>\n&nbsp;&nbsp;&nbsp;1,<br \/>\n&nbsp;&nbsp;&nbsp;2,<br \/>\n&nbsp;&nbsp;&nbsp;&lt;null&gt;,<br \/>\n&nbsp;&nbsp;&nbsp;4<br \/>\n)<\/em><\/p>\n<p><strong>The Code:<\/strong><\/p>\n<p>\n<code><br \/>\n#define END_OF_LIST ((id) -1)<\/p>\n<p>@implementation NSArray (SentinelTerminatedConstructors)<\/p>\n<p>+ (NSArray*) arrayWithSentinelTerminatedObjects:(id) firstObject, ...<br \/>{<br \/>&nbsp;&nbsp;&nbsp;NSMutableArray *array = [NSMutableArray array];<br \/>&nbsp;&nbsp;&nbsp;<br \/>&nbsp;&nbsp;&nbsp;if (firstObject != END_OF_LIST)<br \/>&nbsp;&nbsp;&nbsp;{<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!firstObject)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;firstObject = [NSNull null];<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[array addObject:firstObject];<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id eachObject;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_list argumentList;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_start(argumentList, firstObject);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (END_OF_LIST != (eachObject = va_arg(argumentList, id)))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!eachObject)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eachObject = [NSNull null];<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[array addObject:eachObject];<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;va_end(argumentList);<br \/>&nbsp;&nbsp;&nbsp;}<br \/>&nbsp;&nbsp;&nbsp;<br \/>&nbsp;&nbsp;&nbsp;return array;<br \/>}<\/p>\n<p>@end<br \/>\n<\/code><\/p>\n<p><strong>Some Downsides<\/strong><\/p>\n<p>\n&#8220;<code>arrayWithSentinelTerminatedObjects<\/code>&#8221; is too long of a name.  If you&#8217;ve got a better one, please share!<\/p>\n<p>You won&#8217;t get a compiler-warning if you leave out <code>END_OF_LIST<\/code>, but if you compile with <code>-Wformat<\/code>, you will get a warning if you leave out <code>nil<\/code>.  <a href=\"http:\/\/developer.apple.com\/releasenotes\/Cocoa\/Foundation.html\">The full story<\/a><\/p>\n<blockquote><p>There are six collection creation methods in Foundation which require nil termination to function properly. They are:<\/p>\n<p><code>+[NSArray arrayWithObjects:]<br \/>\n-[NSArray initWithObject:]<br \/>\n+[NSDictionary dictionaryWithObjectsAndKeys:]<br \/>\n-[NSDictionary initWithObjectsAndKeys:]<br \/>\n+[NSSet setWithObjects:]<br \/>\n-[NSSet initWithObjects:]<br \/><\/code><br \/>\nThese methods have been decorated with the <code>NS_REQUIRES_NIL_TERMINATION<\/code> macro, which adds an additional check to invocations of those methods to make sure the nil has been included at the end of the argument list. <strong>This warning is only available when compiling with <code>-Wformat<\/code>.<\/strong><\/p><\/blockquote>\n<p><strong>What do you think?<\/strong><\/p>\n<p>\nFrankly, I haven&#8217;t used <code>END_OF_LIST<\/code>-terminated collection creation enough yet to have a final verdict. So <strong>please let me know what you think<\/strong>!  Was this code useful?  Did it cause problems, or preempt them?  As always, if you have a better solution, please share!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As I&#8217;ve written before, using nil to terminate a variable-length list (eg [NSArray arrayWithObject:foo,bar,nil]) is a bad choice because of how easy it is to get a nil value in Objective-C without knowing it. (Unlike, say C++, doing stuff with nil won&#8217;t cause an exception, leading to some subtle bugs). Well, here is a solution. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,5,4,8],"tags":[156,106,107],"class_list":["post-119","post","type-post","status-publish","format-standard","hentry","category-macosx","category-objective-c","category-programming","category-usability","tag-foundation","tag-nil","tag-nsarray"],"_links":{"self":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts\/119","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/comments?post=119"}],"version-history":[{"count":0,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts\/119\/revisions"}],"wp:attachment":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/media?parent=119"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/categories?post=119"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/tags?post=119"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}