mikeash.com pyblog/friday-qa-2009-10-30-generators-in-objective-c.html commentshttp://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsmikeash.com Recent CommentsThu, 28 Mar 2024 09:55:44 GMTPyRSS2Gen-1.0.0http://blogs.law.harvard.edu/tech/rssHeath Borders - 2010-01-30 05:17:03http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsThus could be further improved with zerocopy system calls. Zero copy allows you to provide the network write buffer pointer and the file read pointer, and does all the copying in systemland. This saves two memory copies. Of course, it only works when copying files exactly as they exist. <br /> <br />This link is primarily about Java, but mentions the appropriate unix system calls. <br /> <br /><a href="http://www.ibm.com/developerworks/library/j-zerocopy/">http://www.ibm.com/developerworks/library/j-zerocopy/</a>037ec3648de1f0d03a6d87e0702777e8Sat, 30 Jan 2010 05:17:03 GMTmikeash - 2009-10-31 19:52:28http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsIn this case, the assignment could be moved. In the general case it could not. This example is meant to illustrate the general case, so many obvious changes which would make that one example easier are not present, because those changes are impossible with a more complex case. <br /> <br />Basically, when trying to understand why the various choices are made, think about generators with at least two GENERAOR_YIELDs in them. Those are the ones where these easier fixes don't make sense. Example: <br /> <br /><code> <br />GENERATOR(id, Zipper(NSArray *a, NSArray *b), (void)) <br />{ <br />&nbsp;&nbsp;&nbsp;&nbsp;NSEnumerator *aenum = [a objectEnumerator]; <br />&nbsp;&nbsp;&nbsp;&nbsp;NSEnumerator *benum = [b objectEnumerator]; <br />&nbsp;&nbsp;&nbsp;&nbsp;GENERATOR_BEGIN(void) <br />&nbsp;&nbsp;&nbsp;&nbsp;{ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(1) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GENERATOR_YIELD([a nextObject]); <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GENERATOR_YIELD([b nextObject]); <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />&nbsp;&nbsp;&nbsp;&nbsp;} <br />&nbsp;&nbsp;&nbsp;&nbsp;GENERATOR_END <br />} <br /></code> <br /> <br />And then consider the code that these macros actually generate. <br /> <br />With something like that, I think the reasoning for why things are placed where they are will make a lot more sense.ccd05ad3ba2bffdafcdcb1b997030c56Sat, 31 Oct 2009 19:52:28 GMTDominik Wagner - 2009-10-31 15:45:46http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsPerhaps i'm mistaken, but should the <br />state = 1; <br />not move up before the beginning of the while loop? I see no need of setting the state every time the block is called, should remove an unnecessary assignment per call and make the use of the intersected switch/while statement easier to understand.3feec3d677d04ce40d37678515cf8d90Sat, 31 Oct 2009 15:45:46 GMTjpc - 2009-10-31 13:01:22http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsA similar approach is also used in <a href="http://www.sics.se/~adam/pt/index.html">http://www.sics.se/~adam/pt/index.html</a> .4d0485fb8c759889b3aff41911f08db5Sat, 31 Oct 2009 13:01:22 GMTmikeash - 2009-10-31 04:25:05http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsPerhaps you're reminded of it because I discuss it at the beginning of the <b>Basic Implementation</b> section.bc5d0eec51eb8c05d2dc88bac47142e4Sat, 31 Oct 2009 04:25:05 GMTClark Cox - 2009-10-31 04:00:48http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsI'm reminded of a similar bit of trickery to implement coroutines in C: <a href="http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html">http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html</a>de63b6bf6fae6ac00cbc91b9361f094eSat, 31 Oct 2009 04:00:48 GMTmikeash - 2009-10-30 20:50:31http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsYou got it exactly right on all counts now. I couldn't summarize it better myself.68ea5d194f574e818d5596faef986170Fri, 30 Oct 2009 20:50:31 GMTnatevw - 2009-10-30 19:29:42http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsThanks. I think the arrangement of the while(1) loop in the first example was tricking me into thinking the do{}while(0) part of GENERATOR_YIELD was more meaningful. I see now that it's really just the standard multi-statement macro idiom, and is meant to be ignored. <br /> <br />The real co-routine trick is not any of the while loops, but combining blocks' preservation of variable state with the blatant use of switch as a goto that takes a variable label.1cc9d881f81d748458dcca129246a60fFri, 30 Oct 2009 19:29:42 GMTmikeash - 2009-10-30 18:56:28http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsYou got the n++ in the right place. I forgot it from the example, but I put it in there now. <br /> <br />As for why to use the switch/while pattern for this example, there's no real reason. Your simple block that just does return count++; is easier to write and simpler to understand. That just exists as an introduction to the more complicated ideas presented farther down. You couldn't write an HTTP parser in this more simplified manner.959836a23cffec979daa27fd94239adbFri, 30 Oct 2009 18:56:28 GMTnatevw - 2009-10-30 18:42:24http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-30-generators-in-objective-c.html#commentsI'm still a little confused by your simpler expanded examples. The GENERATOR_YIELD macro makes sense as a clever way to resume state, but I don't see the analogy to the generator code when you replace something that could be done directly like: <br /> <br />static int (^CountFrom(int start))(void) { <br />&nbsp;&nbsp;&nbsp;&nbsp;__block int count = start; <br />&nbsp;&nbsp;&nbsp;&nbsp;int (^block)(void) = ^{ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return count++; <br />&nbsp;&nbsp;&nbsp;&nbsp;}; <br />&nbsp;&nbsp;&nbsp;&nbsp;return [[block copy] autorelease]; <br />} <br /> <br />with: <br />int (^CountFrom(int start))(void) <br />{ <br />&nbsp;&nbsp;&nbsp;&nbsp;__block int state = 0; <br />&nbsp;&nbsp;&nbsp;&nbsp;__block int n; <br />&nbsp;&nbsp;&nbsp;&nbsp;int (^block)(void) = ^{ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(state) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 0: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n = start; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(1) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state = 1; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return n; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 1: n++; // did I put the increment where you intended? <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />&nbsp;&nbsp;&nbsp;&nbsp;}; <br />&nbsp;&nbsp;&nbsp;&nbsp;return [[block copy] autorelease]; <br />} <br /> <br /> <br />Why are you using a reminiscent-yet-different switch/while pattern in this case?34a165a3a68fe8499007306c03033bd3Fri, 30 Oct 2009 18:42:24 GMT