<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>bugsblog</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/" />
    <link rel="self" type="application/atom+xml" href="http://bugs.doormouse.org/blog/atom.xml" />
    <id>tag:bugs.doormouse.org,2008-05-22:/blog/3</id>
    <updated>2008-08-23T06:06:51Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Open Source 4.12</generator>

<entry>
    <title>One More Cup of Cocoa &apos;Fore I Go</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/08/a-little-more-refactoring.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.171</id>

    <published>2008-08-15T04:01:55Z</published>
    <updated>2008-08-23T06:06:51Z</updated>

    <summary>Well, the Summer of Code is winding down, and I&apos;m going to be spending the next few days whipping up a wiki and a code repository. I just want to make one more quick change before it all comes crashing...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>Well, the Summer of Code is winding down, and I'm going to be spending the next few days whipping up a wiki and a code repository. I just want to make one more quick change before it all comes crashing down around me.</p>

<p>Remember how, in the last post, we made the ALifeWindowController a little smarter about reading configuration files? The improvement was somewhat ironic, since the purpose of that blog was to improve the headless bugs application, and we didn't even modify it to be able to use the new shuffling functionality.</p>

<p>Implementing shuffling naively in the headless bugs implementation would involve copying the new code from ALifeWindowController, which is not very DRY; and in any case, the problem seems to be that the ALifeWindowController has gotten too big for its britches. A mere window doesn't need to know anything about configuration files and options. That's just silly.</p>

<p>Luckily, it's going to be a pretty quick fix to factor out that functionality into a new class: ALifeSimulationController. Instead of the ALifeWindowController doing all the configuration work on its own, it'll outsource it to this rather sassy young class.</p>

<p>Particularly, we're going to put most of the code from ALifeWindowController's <code>- (id)initWithSimulationClass:(Class <ALifeController>)modelClass configuration:(NSDictionary *)theConfiguration;</code> method into ALifeSimulationController, and add a new @property for the simulation controller to the ALifeWindowController class.</p>

<p>Now, all the window controller does is to create a new simulation controller with the options passed to it, and set up its own views and statistics controllers, which is really what it should have been doing in the first place.</p>

<p>This also lets our headless application take advantage of the new value shuffling code with just a few new lines:</p>

<pre><code>simulationController = [[ALifeSimulationController alloc] initWithSimulationClass:selectedPlugin
                                                                    configuration:configuration];
...
for (step = 0; step &lt; numberOfSteps; step++) {
    [simulationController.lifeController update];
}
</code></pre>

<p>Huzzah! We have DRYed out our controllers just a little bit more.</p>

<p>BUT! Lest you think we have arrived at the pinnacle of architecture perfection, this refactoring has brought out a weakness in our abstractions: now we have ALifeControllers, and ALifeSimulationControllers (that have a lifeController attribute that actually does all the work). It seems like we have two different names for the same thing: a class that manages an ALife simulation.</p>

<p>Indeed, I plan to make the current ALifeController protocol into a full-fledged superclass for ALifeControllers, and refactor the ALifeSimulationController functionality into that class. That will let us DRY up the plugins significantly as well, by implementing default functionality for things like statistics and configuration dictionaries.</p>

<p>However, that's a project for another day (or week). For now, I'm just scrambling to finish up this SoC stuff. Goodbye for now, blog, we'll meet again when I catch my breath.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Configuration Shuffling</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/08/configuration-shuffling.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.170</id>

    <published>2008-08-13T05:32:19Z</published>
    <updated>2008-08-23T05:51:49Z</updated>

    <summary>In order to make the headless CocoaBugs actually useful for most models, we want the ability to set a range of random values for a simulation to assume. Then, researchers can build a model, decide on a range of values...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>In order to make the headless CocoaBugs actually useful for most models, we want the ability to set a range of random values for a simulation to assume. Then, researchers can build a model, decide on a range of values to investigate, and send it out to their grid to run many slightly different simulations at once and compare the results.</p>

<p>Building the GUI for this is relatively straightforward. We'll add a shuffle button next to the value slider, which will hide and show a few more controls to set the delta for a given value.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/shuffler.html" onclick="window.open('http://bugs.doormouse.org/blog/images/shuffler.html','popup','width=423,height=167,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/shuffler-thumb-400x157.png" width="400" height="157" alt="shuffler.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>(For now I swiped the shuffle icon from an Apple code sample, I'll be making a new one one of these days.) The shuffle button is type "recessed", so it only shows a border when you hover over it or have selected it (like the Safari bookmark bar), and behaves as a push on/push off button. We also add an IBOutlet for each of the new controls (shuffleDial, shuffleLabel, and plusMinusLabel) as well, so that we can manipulate them programmatically.</p>

<p>Start with the IntegerOptionViewController. We'll add two new @properties to this class, shuffling and delta, and bind them to the values of, respectively the value of the shuffle button, and the values of the delta text field and spinner. In Interface Builder, we can bind the "Hidden" property of these fields to !shuffling, so they are only visible when the button is selected like so:</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="binding.png" src="http://bugs.doormouse.org/blog/images/binding.png" width="301" height="311" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>Now, clicking the shuffle button will hide and show the shuffle controls, and moving the twirly delta selector will change the value of the "delta" instance variable and the associated label.</p>

<p>(The UI for this is pretty bad--spinners suck, there's no way to type in values, and the whole thing is very nonobvious--but for now it'll do.)</p>

<p>Now, in the value method of IntegerOptionViewController, we used to do this:</p>

<pre><code>- (NSNumber *)value;
{
    return [NSNumber numberWithInt:[slider intValue]];
}
</code></pre>

<p>You might think at first glance that we'd replace this with a random number generator, but keep in mind that we want to retain the indeterminacy of the specific value at this point, and save the generation of a value within the range to when a new simulation is actually created. That way, we can send one configuration file to many different clients and see different behavior on each.</p>

<p>So, rather than returning a NSNumber here, we're going to return a dictionary--but only if the value is set to shuffle.</p>

<pre><code>- (NSNumber *)value;
{
    if (shuffling)
        return [NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithInt:[slider intValue]], @"principalValue",
                [NSNumber numberWithInt:delta], @"delta", nil];
    else
        return [NSNumber numberWithInt:[slider intValue]];
}
</code></pre>

<p>Then in our ALifeWindowController, where currently we pass the configuration dictionary straight through to the ALifeController, we'll instead loop through the configuration dictionary and, if we find a dictionary, we'll generate a new random number with the specified principal value and delta.</p>

<pre><code>- (id)initWithSimulationClass:(Class &lt;ALifeController&gt;)modelClass configuration:(NSDictionary *)configuration;
{
...
    // check for shuffled parameters
    for (NSDictionary *configurationOptions in opts) {
        NSString *type = [configurationOptions objectForKey:@"type"];
        NSString *name = [configurationOptions objectForKey:@"name"];
        id entry = [theConfiguration objectForKey:name];
        if ([entry respondsToSelector:@selector(objectForKey:)]
            &amp;&amp; [entry objectForKey:@"shuffle"]) {
            [theConfiguration setValue:[ALifeShuffler shuffleType:type withOptions:entry] forKey:name];
        }
    }
    lifeController = [[modelClass alloc] initWithConfiguration:theConfiguration];
...
}
</code></pre>

<p>Note the new class up my sleeve: ALifeShuffler. This is a new class created to manage shuffling various types of values. Originally, I had the ALifeWindowController class managing shuffling, but it became obvious that this was a pretty poor and inextensible design. (Conceivably, for example, we could want a plugin to be able to define a new configuration type and shuffling method.)</p>

<p>Here's how the ALifeShuffler class works. It has one class method, illustrated above: shuffleType:withOptions:, which takes a string type (as used in the configuration dictionary) and an options dictionary, as maintained by the individual option view controllers.</p>

<p>This method is driven by a singleton shuffleTable object, which maps string types to first-class objects conforming to the ALifeValueShuffler protocol.</p>

<p>This is, in my experience, the standard Objective-C idiom for maintaining such singletons:</p>

<pre><code>static NSDictionary *gShuffleTable = NULL;
...
+ (NSDictionary *)shuffleTable;
{
    if (!gShuffleTable) {
        gShuffleTable = [[NSMutableDictionary dictionary] retain];
        [gShuffleTable setValue:[[[IntegerShuffler alloc] init] autorelease]
                         forKey:@"Integer"];
        [gShuffleTable setValue:[[[FloatShuffler alloc] init] autorelease]
                         forKey:@"Float"];
    }
    return gShuffleTable;
}
</code></pre>

<p>Note that the gShuffleTable is never released, since classes are never deallocated; traditionally, this is a memory leak, but since we only ever create the thing once, it's not too bad. If more experienced Objective-C coders want to show me the error of my ways, I'm very amenable.</p>

<p>Since the value shuffler classes are so small, they're defined inline in the ALifeShuffler.m file:</p>

<pre><code>@interface IntegerShuffler : NSObject &lt;ALifeValueShuffler&gt; @end
@implementation IntegerShuffler
- (id)shuffle:(NSDictionary *)options;
{
    int p = [[options valueForKey:@"principalValue"] intValue];
    int d = [[options valueForKey:@"delta"] intValue];

    int v = p + (random() % (2 * d + 1)) - d;

    return [NSNumber numberWithInt:v];
}
@end
</code></pre>

<p>Theoretically, a plugin class could define their own type and shuffler class for this, and add it to the [ALifeShuffler shuffleTable]; however, there is currently no functionality for defining new types of option view controllers (which would probably be done in a similar way), which would be a prerequisite of such work.</p>

<p>Next time: a look at refactoring out some of this functionality from ALifeWindowController into a more MVC-acceptible class.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>ALife XI</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/08/alife-xi.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.167</id>

    <published>2008-08-09T17:53:20Z</published>
    <updated>2008-08-09T17:58:49Z</updated>

    <summary>The ALife conference was amazing. Our research, though there is still a world of work to do, was very well-received by the audience, and we have many new ideas for directions to take it in. (As if we didn&apos;t have...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>The ALife conference was amazing. Our research, though there is still a world of work to do, was very well-received by the audience, and we have many new ideas for directions to take it in. (As if we didn't have too many of those before!) We let Mark present it, because he's a lot better at working the crowd than Noah or I.</p>

<p>I am still completely jetlagged, but recovering slightly in a London pub. I actually did manage to get a little coding done in Winchester, so expect a blog post about that either this evening or tomorrow.</p>

<p>There weren't as many novel models to see as I thought. Perhaps the most exciting thing was a keynote on creating lifelike structures purely out of oil drops in suspension in a controlled-pH solution. Pretty nifty, pretty nifty.</p>

<p>The next one will be in 2010, apparently; I certainly plan to attend! Hopefully, CocoaBugs will assist some in the community in making some revolutionary new stuff.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Still busy!</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/07/still-busy.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.166</id>

    <published>2008-07-28T05:19:40Z</published>
    <updated>2008-08-09T17:53:12Z</updated>

    <summary>Alright, so, I haven&apos;t done much the past few days, and won&apos;t be doing much for at least a week. A few colleagues and I are scrambling to prepare our presentation at ALife XI in Winchester, UK (leaving on Friday),...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>Alright, so, I haven't done much the past few days, and won't be doing much for at least a week. A few colleagues and I are scrambling to prepare our presentation at ALife XI in Winchester, UK (leaving on Friday), I just got re-contracted at the last minute for the Portland company I spoke of earlier, and I have to get my life completely moved from Westmoreland to the heart of Downtown this Thursday before I get on a plane Friday morning. Needless to say, I am harried.</p>

<p>I'll try and do some hacking on CocoaBugs during the ALife conference, but I have a feeling I'll be busier learning about exciting new models than coding. (I hope.)</p>

<p>Bear with me! By the 18th of next month, I'll have a fairly useful headless mode completed, as well as some good documentation and a few new models to tinker with.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Headless Cocoa Bugs</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/07/headless-cocoa-bugs.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.164</id>

    <published>2008-07-23T20:47:41Z</published>
    <updated>2008-08-09T17:48:14Z</updated>

    <summary>...is a good name for a rock band. Last time, we saw how to create nice friendly configuration files for CocoaBugs. Today, I&apos;ll be talking about how to use those config files to run ALife simulations headlessly in a new...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>...is a good name for a rock band.</p>

<p>Last time, we saw how to create nice friendly configuration files for CocoaBugs. Today, I'll be talking about how to use those config files to run ALife simulations headlessly in a new command-line (CLI) client.</p>

<p>We can create a new CLI target by right-clicking the "Targets" section in XCode, and picking Add -> New Target... We want a command-line app, so choose "Shell Tool" from the "Cocoa" section. (This is a "Target for building a command-line tool that uses Cocoa APIs", which is exactly what we want.) I'll name it HeadlessBugs.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="new target.png" src="http://bugs.doormouse.org/blog/images/new%20target.png" width="162" height="103" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>This will create a new target with no files associated with it. We need at least a main function for it to actually do anything.</p>

<p>Our default main.m file calls NSApplicationMain, which loads nib files and classes as specified in the Info.plist in the app bundle; this target is a raw executable, with no bundle, Info.plist, or nib files, so we want to make our own. So we'll create a new Objective-C file, headless_main.m.</p>

<p>Since we're not taking advantage of the NSApplicationMain in this file, we need to create our own NSAutoreleasePool. Parsing of command-line options is done with the NSUserDefaults class. As a first guess, we're going to want to support three options:</p>

<ul>
<li>Input configuration file</li>
<li>Output directory path</li>
<li>Number of generations to run for</li>
</ul>

<p>Let's try this to begin, for headless_main.m:</p>

<pre><code>#import &lt;Cocoa/Cocoa.h&gt;

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSUserDefaults *args = [NSUserDefaults standardUserDefaults];

    NSLog(@"Configuration file: %@", [args stringForKey:@"f"]);
    NSLog(@"Output directory file: %@", [args stringForKey:@"o"]);
    NSLog(@"Number of steps: %d", [args integerForKey:@"s"]);

    [pool release];
    return 0;
}
</code></pre>

<p>This file can be included in the target by dragging it to the "Compile Sources" phase of the HeadlessBugs target.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="compile sources.png" src="http://bugs.doormouse.org/blog/images/compile%20sources.png" width="195" height="54" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>After selecting the target and building, we can try it in a terminal:</p>

<pre><code>Glaukopis-Athena:Debug d$ ./HeadlessBugs -f foo.cocoabugs -o ~/Desktop/runs -s 5000
2008-07-29 15:19:56.563 HeadlessBugs[6656:10b] Configuration file: foo.cocoabugs
2008-07-29 15:19:56.565 HeadlessBugs[6656:10b] Output directory file: /Users/d/Desktop/runs
2008-07-29 15:19:56.565 HeadlessBugs[6656:10b] Number of steps: 5000
</code></pre>

<p>Whoo! Nearly there.</p>

<p>Now we need to make this actually do something. Unfortunately, as written, we can't just import our AppController code and get plugin classes from there, since the AppController depends on all sorts of GUI stuff that we don't need or care about. So, we're going to factor the plugin loading code out into an ALifePluginLoader class that doesn't depend on anything else. To avoid needless object creation and management, I'm going to make the three plugin related methods class methods:</p>

<pre><code>+ (BOOL)plugInClassIsValid:(Class)plugInClass;
+ (NSMutableArray *)allPlugIns;
+ (NSMutableArray *)allPlugInPaths;
</code></pre>

<p>Now we can import ALifePluginLoader.h into our AppController and headless_main.m files, and use them from there.</p>

<pre><code>NSArray *plugins = [ALifePluginLoader allPlugIns];
NSString *configurationFile = [args stringForKey:@"f"];
NSString *outputDirectory = [args stringForKey:@"o"];
int numberOfSteps = [args integerForKey:@"s"];

if (!(configurationFile &amp;&amp; outputDirectory &amp;&amp; numberOfSteps))
    printf("Usage: HeadlessBugs -f &lt;config filename&gt; -o &lt;output directory path&gt; -s &lt;number of steps&gt;\n");

NSDictionary *data = [NSDictionary dictionaryWithContentsOfFile:configurationFile];
NSString *identifier = [data objectForKey:@"identifier"];

Class &lt;ALifeController&gt; selectedPlugin;
for (Class &lt;ALifeController&gt; plugin in plugins) {
    if ([[plugin name] isEqual:identifier]) {
        selectedPlugin = plugin;
        break;
    }
}

if (!selectedPlugin)
    printf("Plugin class not found. Make sure it's installed.");
</code></pre>

<p>Once we've found the selected plugin, we want to run it for the specified number of steps:</p>

<pre><code>NSDictionary *configuration = [data objectForKey:@"configuration"];
id &lt;ALifeController&gt; controller = [[selectedPlugin alloc] initWithConfiguration:configuration];

int step;
for (step = 0; step &lt; numberOfSteps; step++) {
    printf("Step %d\n", step);
    [controller update];
}

printf("Done.\n");
</code></pre>

<p>It works! Of course, despite what the code says, we are far from done. We need a way for the headless app to generate a directory of output information, especially the statistics over time for the run. Doing this will require refactoring the statistics controller to not depend on a window to show its results in, as well as some careful thought about exactly what kinds of data to keep. Soon, I hope!</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Busy!</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/07/busy.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.165</id>

    <published>2008-07-21T16:19:21Z</published>
    <updated>2008-08-09T17:49:49Z</updated>

    <summary>Sorry about no posts for a while--I&apos;m so bad about that. I&apos;ve been super-swamped the past few weeks helping out a Portland company with their iPhone app. Rest assured that I am on track. I&apos;ll post tomorrow about some first...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>Sorry about no posts for a while--I'm so bad about that. I've been super-swamped the past few weeks helping out a Portland company with their iPhone app. Rest assured that I am on track. I'll post tomorrow about some first steps towards making CocoaBugs headless.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Saving and opening files</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/07/saving-and-opening-files.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.163</id>

    <published>2008-07-13T19:18:04Z</published>
    <updated>2008-08-09T17:35:26Z</updated>

    <summary>Previously, we saw how we could build a framework GUI to translate the configuration options for a given ALife model into a configuration window that could provide an NSDictionary of key-value pairs to give to our ALife models. That was...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>Previously, we saw how we could build a framework GUI to translate the configuration options for a given ALife model into a configuration window that could provide an NSDictionary of key-value pairs to give to our ALife models. That was pretty keen.</p>

<p>However, now that we can generate configurations, we want to be able to save those configuration files, and, if possible, execute them headlessly from the command-line, for grid computation purposes. The use case is, we define some parameters (some of them randomly set within a range), and send that configuration out to the grid. Then we can examine the results later, and pick out those that display interesting behavior for further study.</p>

<p>We'll implement the GUI and backend support for randomized input value later. Here, we'll look at</p>

<ol>
<li>the process for generating PList configuration files from our configuration,</li>
<li>being able to open those configuration files from the GUI, and</li>
<li>creating a command-line executable to run a model for a certain number of generations headlessly.</li>
</ol>

<p>The first is pretty dead-easy. Recall that we've got an ALifeConfigurationViewController, which loads the configuration options for a specified ALifeController class and displays the options (OptionViewControllers, to be precise) in a GUI. Each of the OptionViewControllers knows its current value, and the key with which it's associated; this allows us to build a dictionary of key:value pairs which we can feed to the ALifeController to initialize a configuration.</p>

<p>We've seen before how easy it is to build dictionaries from a plist file; it turns out it's just as easy to go the other way. We'll add a button to our configuration window, next to the Start button to export the current configuration, with a corresponding IBAction:</p>

<pre><code>- (IBAction)actionExportConfiguration:(id)sender;
</code></pre>

<p>All this action does is show a save panel, specifying a file extension which our application will support:
    - (IBAction)actionExportConfiguration:(id)sender;
    {
        NSSavePanel *savePanel = [NSSavePanel savePanel];
        [savePanel setRequiredFileType:@"cocoabugs"];
        [savePanel beginSheetForDirectory:nil
                                     file:nil
                           modalForWindow:[self window]
                            modalDelegate:self
                           didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:)
                              contextInfo:nil];
    }
This method shows a save panel in a window-modal sheet, and our ALifeConfigurationWindowController will get sent the savePanelDidEnd:... selector when that panel is closed by the user (by pressing either "Save" or "Cancel").</p>

<p>In this method, we want to:
1. Check if the Save button was clicked;
2. Generate a dictionary specifying the configuration and a class identifier;
3. Write the dictionary to a file.
The code is fairly self-explanatory, utilizing NSDictionary's -writeToFile: method to save the dictioniary in plist format:</p>

<pre><code>- (void)savePanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode  contextInfo:(void  *)contextInfo;
{
    if (returnCode == NSOKButton) {
        NSDictionary *configuration = [configurationViewController configuration];
        NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:
                                [[self selectedClass] name], @"identifier",
                                configuration, @"configuration", nil];
        [data writeToFile:[sheet filename] atomically:YES];
    }
}
</code></pre>

<p>Now we need to do a little work to allow these files to be double-clickable. In XCode, the Get Info window for the CocoaBugs target has a "Properties" tab which lets us edit the Info.plist values directly. Here we can add a new document type for our app to support:</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/cocoabugs%20document%20types.html" onclick="window.open('http://bugs.doormouse.org/blog/images/cocoabugs%20document%20types.html','popup','width=745,height=673,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/cocoabugs document types-thumb-400x361.png" width="400" height="361" alt="cocoabugs document types.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>Now when a file with extension .cocoabugs is double-clicked, our app will be sent the message</p>

<pre><code>- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
</code></pre>

<p>This method will be very similar to the actionStartSimulation method in our ALifeConfigurationWindowController.</p>

<pre><code>- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
    NSDictionary *data = [NSDictionary dictionaryWithContentsOfFile:filename];

    NSString *identifier = [data objectForKey:@"identifier"];
    NSDictionary *configuration = [data objectForKey:@"configuration"];

    Class selectedPlugin;
    NSArray *plugins = [self allPlugIns];
    for (Class &lt;ALifeController&gt; plugin in plugins) {
        if ([[plugin name] isEqual:identifier]) {
            selectedPlugin = plugin;
            break;
        }
    }

    ALifeWindowController *simulationWindow =
        [ALifeWindowController windowControllerForModel:selectedPlugin
                                      withConfiguration:configuration];

    return YES;
}
</code></pre>

<p>We loop through the loaded plugins, looking for the plugin matching the identifier set in the plist; once found, we open a new simulation window with an ALifeController initialized with the specified configuration.</p>

<p>Now we can set some options in the configuration controller, export to a file, and double-click it to run the simulation.</p>

<p>Nice!</p>

<p>So, that's parts 1 and 2 under our belts. Part 3 will take a little more doing, and a little more refactoring. You'll just have to wait and see how that pans out... because I haven't done it yet. OH THE HUMANITY</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Plugin Configuration: An Adventure in GUIland</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/07/plugin-configuration-an-advent.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.162</id>

    <published>2008-07-13T00:10:56Z</published>
    <updated>2008-08-09T17:27:54Z</updated>

    <summary>So, we&apos;ve got plugins, but we don&apos;t have any way to actually run them yet. For that, we need a GUI. Implementing all this in a relatively sane way required a fair amount of work and classes, so I won&apos;t...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>So, we've got plugins, but we don't have any way to actually run them yet. For that, we need a GUI.</p>

<p>Implementing all this in a relatively sane way required a fair amount of work and classes, so I won't go into as much detail here as I have on other posts. I've created something like a dozen new classes and nib files to support the configuration and execution of ALife models.</p>

<p>I haven't been documenting this as I code, so I don't have a nice step-by-step genesis of the changes as I've done for other posts. Instead, here's a walkthrough of what happens to make this window:</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/configuration.html" onclick="window.open('http://bugs.doormouse.org/blog/images/configuration.html','popup','width=438,height=144,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/configuration-thumb-400x131.png" width="400" height="131" alt="configuration.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>and then to turn it into this window:</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/game%20of%20life%20window.html" onclick="window.open('http://bugs.doormouse.org/blog/images/game%20of%20life%20window.html','popup','width=830,height=892,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/game of life window-thumb-400x429.png" width="400" height="429" alt="game of life window.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>Briefly, then:</p>

<ol>
<li>When "New" is picked from the File menu, a list of plugins (as described in the last post) is generated by the AppController, and a new ALifeWindowController is created and fed with these classes.</li>
<li>The ALifeWindowController creates a list of model names to populate the left-hand side.</li>
<li>Once a model's name is picked, the ALifeWindowController queries the selected ALifeController for its configuration (an addition to the ALifeController protocol).</li>
<li>The ALifeConfigurationViewController on the right-hand side is populated with this list of configuration options, which might look something like this:
<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/game%20of%20life%20configuration.html" onclick="window.open('http://bugs.doormouse.org/blog/images/game%20of%20life%20configuration.html','popup','width=505,height=335,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/game of life configuration-thumb-400x265.png" width="400" height="265" alt="game of life configuration.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></li>
<li>For each entry in the configuration array, a new *OptionViewController is created and added to the main configuration view. So far, there are only IntegerOptionViewControllers, and FloatOptionViewControllers, which are virtually identical except for the types they handle. (There is a lot of DRYing up that needs to be done on this code.)</li>
<li>Each OptionViewController manages its own state. When the "Start" button is clicked, the ALifeConfigurationViewController is queried for its state, which builds a dictionary of key-value pairs based on the keys and values stored by each OptionViewController.</li>
<li>This dictionary is fed to the ALifeController in question, to which protocol has been added the method initWithConfiguration:(NSDictionary *)configuration. The ALifeController creates a new instance of its model initialized as specified.</li>
<li>A new ALifeWindowController is created, which manages StatisticsViews as described before. The ALifeController is queried for a view, which is then added to the ALifeWindowController's window.</li>
<li>That's it! (Whew.)</li>
</ol>

<p>Next time, exporting configuration options to a standalone file, and reading them back in when they're double-clicked.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Bugs Plugins</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/07/bugs-plugins.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.161</id>

    <published>2008-07-08T23:51:32Z</published>
    <updated>2008-08-09T17:09:52Z</updated>

    <summary>In the last post, I intimated that moving our models out into their own plugins was going to be really, really easy. It turns out that that&apos;s absolutely true! How nice. We already had several models, loosely coupled with the...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>In the last post, I intimated that moving our models out into their own plugins was going to be really, really easy. It turns out that that's absolutely true! How nice.</p>

<p>We already had several models, loosely coupled with the program logic by the ALifeController protocol, with their own models, views, and controllers. All we need to do to complete the picture is to move them from the main app bundle into their own bundles, which can then be dynamically loaded by the CocoaBugs app.</p>

<p>In XCode, we can create a Cocoa bundle straightforwardly. Choose New Project, and pick Bundle > Cocoa Bundle.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/cocoa%20bundle.html" onclick="window.open('http://bugs.doormouse.org/blog/images/cocoa%20bundle.html','popup','width=790,height=701,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/cocoa bundle-thumb-400x354.png" width="400" height="354" alt="cocoa bundle.png" class="mt-image-center" style="" /></a></span></p>

<p>This makes a new bundle project: all the code in the bundle will be compiled and linked as usual, but instead of making a double-clickable executable, the executable is used merely as an entry point to access the classes created in the bundle.</p>

<p>So, we can copy, for example, code to implement the Game of Life (following the ALifeController protocol) into this new project to make a CocoaBugs plugin.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/game%20of%20life%20bundle.html" onclick="window.open('http://bugs.doormouse.org/blog/images/game%20of%20life%20bundle.html','popup','width=853,height=609,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/game of life bundle-thumb-400x285.png" width="400" height="285" alt="game of life bundle.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>We also make a few changes to the Info.plist of the file:</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/game%20of%20life%20plist.html" onclick="window.open('http://bugs.doormouse.org/blog/images/game%20of%20life%20plist.html','popup','width=507,height=232,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/game of life plist-thumb-400x183.png" width="400" height="183" alt="game of life plist.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>The most important change is the value for "Principal class". This is the entry point to our bundle; once it's loaded, the main app can query the bundle for its principal class, and interacts with the Game of Life code from there. Here we've set it to the ControllerOfLife class.</p>

<p>(Note that there is another plist, "GameOfLife.plist", which contains the CocoaBugs-specific information about the GameOfLife model.)</p>

<p>We can also change the file extension of the compiled bundle, by getting info on the bundle target. Here we'll use .plugin.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/wrapper%20extension.html" onclick="window.open('http://bugs.doormouse.org/blog/images/wrapper%20extension.html','popup','width=745,height=673,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/wrapper extension-thumb-400x361.png" width="400" height="361" alt="wrapper extension.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>Now, the tricky bit is getting these to actually load from our main app. After building and copying the product into ~/Application Support/CocoaBugs/PlugIns/, we can do the following in our app controller (prepare for Code Overload):</p>

<pre><code>+ (NSMutableArray *)allPlugIns;
{
    NSBundle *currBundle;
    Class currPrincipalClass;

    NSMutableArray *plugIns = [NSMutableArray array];
    for (NSString *plugInPath in [self allPlugInPaths]) {
        currBundle = [NSBundle bundleWithPath:plugInPath];
        NSLog(@"Checking %@", [currBundle bundleIdentifier]);
        if (currBundle) {
            currPrincipalClass = [currBundle principalClass];
            if(currPrincipalClass &amp;&amp; [self plugInClassIsValid:currPrincipalClass])  // Validation
            {
                [plugIns addObject:currPrincipalClass];
            }
        }
    }

    NSSortDescriptor *nameSort = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES] autorelease];
    [plugIns sortUsingDescriptors:[NSArray arrayWithObjects:nameSort, nil]];

    NSLog(@"%d plugins loaded", [plugIns count]);
    return plugIns;
}

+ (BOOL)plugInClassIsValid:(Class)plugInClass;
{
    return [plugInClass conformsToProtocol:@protocol(ALifeController)];
}

+ (NSMutableArray *)allPlugInPaths;
{
    NSString *ext = @"plugin";
    NSString *appSupportSubpath = @"Application Support/CocoaBugs/PlugIns";

    NSArray *librarySearchPaths;
    NSMutableArray *bundleSearchPaths = [NSMutableArray array];
    NSMutableArray *allBundles = [NSMutableArray array];

    // find the libraries
    librarySearchPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask - NSSystemDomainMask, YES);

    // we'll look in the App Support/CocoaBugs/PlugIns directory in each library
    for (NSString *currPath in librarySearchPaths) {
        [bundleSearchPaths addObject:[currPath stringByAppendingPathComponent:appSupportSubpath]];
    }
    [bundleSearchPaths addObject:[[NSBundle mainBundle] builtInPlugInsPath]];

    // check for .plugin files
    for (NSString *currPath in bundleSearchPaths) {
        for (NSString *currBundlePath in [[NSFileManager defaultManager] directoryContentsAtPath:currPath]) {
            if ([[currBundlePath pathExtension] isEqualToString:ext]) {
                [allBundles addObject:[currPath stringByAppendingPathComponent:currBundlePath]];
            }
        }
    }

    return allBundles;  
}
</code></pre>

<p>It seems like a lot, but it's pretty straightforward. (Mostly, it's just boilerplate from Apple's documentation on plugin loading design patterns.) From bottom to top:</p>

<ol>
<li>allPlugInPaths returns all the directories we want to search for plugins. In the current code, we look in the app's own PlugIns directory; the /Library/Application Support/ directory, and ~/Library/Application Support/.</li>
<li>plugInClassIsValid validates a purported plugin: here, we just check to see if the principal class conforms to our ALifeController protocol.</li>
<li>allPlugIns uses those two functions to load and check bundles, building an array sorted by name of each plugin and returning them.</li>
</ol>

<p>We can then use the returned array of plugins to build a configuration window for each plugin. That'll be next time.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Express Abstractionism</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/07/express-abstractionism.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.160</id>

    <published>2008-07-04T18:19:36Z</published>
    <updated>2008-08-09T16:50:37Z</updated>

    <summary>The last few posts have gone into detail on some techniques to reduce the coupling between different parts of the CocoaBugs framework. Specifically, we want to move towards a plugin-based solution for running different ALife models. Plists and key-value observation...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>The last few posts have gone into detail on some techniques to reduce the coupling between different parts of the CocoaBugs framework. Specifically, we want to move towards a plugin-based solution for running different ALife models.</p>

<p>Plists and key-value observation are the main tool we've used so far. We've managed to greatly reduce the amount of knowledge our app controller needs to have about the ALife models to provide statistics and configuration services.</p>

<p>However, there is still one huge amount of "knowledge" our AppController has about the models it's running, and is the most significant barrier our framework needs to surmount. See if you can spot it:</p>

<pre><code>AppController.m:
ControllerOfLife *lifeController = [[ControllerOfLife alloc] init];
</code></pre>

<p>Eep! That is just no good at all.</p>

<p>The first thing we can do is define an Objective-C protocol for the interface of an ALife controller. That way, we can be sure that the app controller can talk to the ALife controllers, without needing to be compiled alongside them or have knowledge about their implementation.</p>

<p>For now, we'll just include a few methods that most every ALife model will probably implement.</p>

<pre><code>@protocol ALifeController &lt;NSObject&gt;

// update the simulation
- (void)update;
// get a view for the simulation
- (NSView *)viewWithFrame:(NSRect)frame;
// get the properties for the simulation
// includes "statistics" key, for statistics descriptions
- (NSDictionary *)properties;
// the object to listen to for statistics updates
- (id)statisticsCollector;

@end
</code></pre>

<p>Now we can declare that our ControllerOfLife implements this protocol in its header file:</p>

<pre><code>#import "ALifeController.h"

@interface ControllerOfLife : NSObject &lt;ALifeController&gt; {
...
}
</code></pre>

<p>Now, we can have a simulationController property of our AppController, defined to be any old object that implements the protocol:</p>

<pre><code>id &lt;ALifeController&gt; simulationController;
</code></pre>

<p>However, we still haven't modularized the code enough to keep from hard-coding the name of the actual controller class when initializing the model in our AppController, as above.</p>

<p>The last piece of the puzzle is going to solve this problem and the question of installing new ALife models in one fell swoop: we'll be moving the code for models entirely out of the CocoaBugs project, into their own code bundles---plugins. It turns out that this is going to be really, really easy. Stay tuned!</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Cocoa Mystery of the Moment</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/07/cocoa-mystery-of-the-moment.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.157</id>

    <published>2008-07-03T02:04:03Z</published>
    <updated>2008-07-03T02:11:38Z</updated>

    <summary>Cocoa gets a little too helpful with missing methods...?</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>So I'm throwing together an XCode template project for new ALife models--just enough to show the proper MVC design and the bare minimum of classes and methods needed for a CocoaBugs plugin--and I run into a gem of a compiler warning on this line in the drawRect method of the view:</p>

<pre><code>[[NSString stringWithFormat:@"%d", simulation.generation]
 drawInRect:[self bounds]];
</code></pre>

<p>Here's the warning.</p>

<p><i>/Users/d/Desktop/ALife Plugin/LifeView.m:38: warning: multiple methods named '-drawInRect:' found
/Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSImageRep.h:43: warning: using '-(BOOL)drawInRect:(NSRect)rect'
/Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSStringDrawing.h:24: warning: also found '-(void)drawInRect:(NSRect)rect'</i></p>

<p>Now, that seems pretty legit at first glance. NSString, despite my memory, has no drawInRect: method; it's drawInRect:withAttributes: for unattributed strings.</p>

<p>The thing that boggles me is that neither of the two candidate methods have any chance of working on the object that I am plainly calling them on. The compiler, it seems, can clearly see that I am making just a plain-old NSString, not an NSImageRep or NSAttributedString.</p>

<p>There's the possibility that I could be injecting a drawInRect: method to the NSString class at runtime, so it makes sense that this wouldn't be a straight-up error, but these specific warnings, I admit, confuse me greatly.</p>

<p>The take-away message: I still have a lot to learn about Objective-C method dispatching.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>What&apos;s the deal with .plists?</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/06/whats-the-deal-with-plists.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.155</id>

    <published>2008-06-30T20:43:42Z</published>
    <updated>2008-07-01T09:31:16Z</updated>

    <summary>In the last entry we talked about one way to abstract away the differences between ALife models (specifically, differences in relevant statistics) by connecting classes with key-value observation. However, the solution was a little constricting and nonextensible. Let&apos;s leverage the RAW POWER OF XML to make our job a little easier...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>In the last entry we talked about one way to abstract away the differences between ALife models (specifically, differences in relevant statistics) by connecting classes with key-value observation. However, the solution was a little constricting and nonextensible.</p>

<p>In particular, the way we coded which statistics an ALife model would support was a little brittle. We used a simple NSDictionary, with keys corresponding to the keypath of a statistics collector object, and the value as a human-readable title. Though this works for the current implementation, it also means that there is no way to add other configuration options: for example, most of the statistics that we'll collect will be single values, while some will be sets of values; with our simple dictionary-based definition of statistics, there is no good way to differentiate between these or other options.</p>

<p>To resolve this impasse, we could just make the dictionary more complicated. In particular, we might want each entry in the dictionary to be, instead of a simple title, another dictionary object containing key-value pairs for information like the title, key path or other information.</p>

<p>In fact, this is actually what CocoaBugs does. However, doing this in code gets pretty ugly: Cocoa doesn't have simple dictionary literals like scripting languages, and maintaining large dictionaries of data like that gets messy fast. Where in Ruby we could say something like,</p>

<pre><code>statistics = {:population =&gt; {:title =&gt; "Population",
                              :key_path =&gt; "population",
                              :singular =&gt; true},
              :birth_rate =&gt; { ... }}
</code></pre>

<p>in Cocoa it gets a little uglier:</p>

<pre><code>NSMutableDictionary *statisticsDescriptors = [NSMutableDictionary dictionary];

// add the population entry
[statisticsDescriptors addObject:[NSDictionary dictionaryWithObjectsAndKeys:
                                  @"Population", @"title",
                                  @"population", @"keyPath",
                                  [NSValue valueWithBool:YES], @"singular", nil]];

// add the birth rate entry
...
</code></pre>

<p>That's just no good at all.</p>

<p>Luckily, Cocoa provides some nice frameworks for allowing us to define structured data like this in a more maintainable way: property lists, more commonly known by their file extension, .plist.</p>

<p>A plist (pronounced, as far as I know, as "pea-list") is an XML file which describes keyed data according to a simple, well-defined syntax. The iTunes library, for example, is a .plist, storing information about songs and playlists; most preference files in Mac OS X are .plists.</p>

<p>In our case, we're going to build a plist which will describe the statistics values for an ALife model, and which we can later extend to encompass the more complicated parameters an artificial life model might accept.</p>

<p>In this case, I'll be using some existing code for Conway's Game of Life to illustrate this technique. Thanks to the object-oriented nature of Cocoa and CocoaBugs, it was straightforward to drop this into the CocoaBugs codebase. (There will be more on the specifics of this in a later post.)</p>

<p>I created a new StatisticsOfLife class in the Game of Life bundle which acts like the WorldStatistics class in the Packard Bugs code discussed previously. It listens for changes to the "generation" property of the GameOfLife object, and updates its own statistics properties every generation. Here I'll just be collecting population statistics.</p>

<pre><code>- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context;
{
    if ([keyPath isEqual:@"generation"]) {
        [self updateStatistics];
    }
}

- (void)updateStatistics;
{
    NSLog(@"Collating statistics...");

    // population
    int pop = 0;
    for (NSMutableArray *row in game.grid) {
        for (CellOfLife *cell in row) {
            if (cell.alive)
                pop++;
        }
    }
    self.population = [NSSet setWithObject:[NSNumber numberWithInt:pop]];
}
</code></pre>

<p>(Note that I'm still using NSSets to store all statistics data---we'll fix that later on.)</p>

<p>In the WorldStatistics class, we defined a "descriptions" method so our app controller could tie the model to the CocoaBugs statistics controller. Now, we can use a .plist to do the same job.</p>

<p>Using Apple's Property List Editor app, it's simple to make such a plist:
<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://bugs.doormouse.org/blog/images/plist%20editor.html" onclick="window.open('http://bugs.doormouse.org/blog/images/plist%20editor.html','popup','width=539,height=458,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://bugs.doormouse.org/blog/images/plist editor-thumb-400x339.png" width="400" height="339" alt="plist editor.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>This translates into the relatively readable XML:</p>

<pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
    &lt;key&gt;statistics&lt;/key&gt;
    &lt;dict&gt;
        &lt;key&gt;population&lt;/key&gt;
        &lt;dict&gt;
            &lt;key&gt;keyPath&lt;/key&gt;
            &lt;string&gt;population&lt;/string&gt;
            &lt;key&gt;title&lt;/key&gt;
            &lt;string&gt;Population&lt;/string&gt;
            &lt;key&gt;singular&lt;/key&gt;
            &lt;true/&gt;
        &lt;/dict&gt;
    &lt;/dict&gt;
&lt;/dict&gt;
&lt;/plist&gt;
</code></pre>

<p>Now in the GameOfLife controller class, ControllerOfLife, we'll add a bit to the init method to load the contents of this file into an NSDictionary:</p>

<pre><code>NSString *thePath = [[NSBundle mainBundle] pathForResource:@"GameOfLife" ofType:@"plist"];
properties = [[NSDictionary dictionaryWithContentsOfFile:thePath] retain];
</code></pre>

<p>This "properties" dictionary will store the configuration parameters for the GameOfLife model. As suggested by the screenshot, the data model looks something like this:</p>

<pre><code>statistics:
  population:
    keyPath: "population"
    title: "Population"
    singular: YES
</code></pre>

<p>(Later, we'll probably add a "parameters" dictionary at the same level as "statistics" to store options for initializing the model.)</p>

<p>So, where we used to do something like this:</p>

<pre><code>WorldStatistics.m:
- (NSDictionary *)descriptions;
{
  return [NSDictionary dictionaryWithObjectsAndKeys:
          @"Population",     @"population",
          @"Births (total)", @"births",
          @"Deaths (total)", @"deaths",
          @"Average age",    @"averageAge",
          @"Mortality age",  @"mortalityAge",
          @"Gene survival",  @"geneSurvival", nil];
}

BugsController.m:
- (void)awakeFromNib;
{
... 
    // set up statistics
    statistics = [[WorldStatistics alloc] initWithWorld:world];
    statisticsController.source = statistics;

    // get descriptions of collated statistics
    NSDictionary *descriptions = [statistics descriptions];
    for (NSString *key in descriptions) {
        [statisticsController registerForPath:key
                                         name:[descriptions objectForKey:key]];
    }
...
}
</code></pre>

<p>we can now do this:</p>

<pre><code>StatisticsController.m:
- (void)setSource:(id)statisticsCollector
    forStatistics:(NSDictionary *)descriptions;
{
    self.source = statisticsCollector;

    for (NSDictionary *description in [descriptions allValues]) {
        [self registerForPath:[description objectForKey:@"keyPath"]
                         name:[description objectForKey:@"title"]];
    }
}

AppController.m:
[statisticsController setSource:[simulationController statisticsCollector]
                          forStatistics:[[simulationController properties]
                                         objectForKey:@"statistics"]];
</code></pre>

<p>Now we can collect statistics on the Game of Life. Once we build-and-go, here's how the population grows on a 150 x 150 board initialized to the r-pentomino (1000 generations):
<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="game of life stats.png" src="http://bugs.doormouse.org/blog/images/game%20of%20life%20stats.png" width="264" height="133" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>There is one major downside to implementing statistics in this way. Where before, we could maintain the statistics for a model in one file, here we need to maintain two files: GameOfLife.plist and StatisticsOfLife.m. If we add a statistics key to GameOfLife.plist, and don't implement a corresponding property in StatisticsOfLife, we'll get a key-value coding error.</p>

<p>However, the advantages of the solution more than outweigh this downside. Using .plists for configuring our statistcs gives us:</p>

<ul>
<li><p><em>Less coupling.</em> The StatisticsController never talks to the StatisticsOfLife directly; all it knows is that, based on the .plist, the class referenced by the ControllerOfLife as its statistics collector is key-value compliant for certain keys. (Though we'll never use this particular feature, this means that we could even use built-in Cocoa dictionaries as statistics collection objects, since they are key-value compliant.)</p></li>
<li><p><em>Future extensibility.</em> If we want to be able to specify that certain statistics objects are of a certain numeric type, should be represented in a certain way, or should only be collected under certain circumstances, we can just add a key to the plist entry, and not have to worry about maintaining statistics information in code.</p></li>
</ul>

<p>In the next post, we'll look at some more advanced refactoring using Cocoa protocols and bundles. How exciting!</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Module configuration</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/06/module-configuration.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.149</id>

    <published>2008-06-25T04:07:21Z</published>
    <updated>2008-07-01T09:16:08Z</updated>

    <summary>CocoaBugs aims to provide a framework for user interface, statistics gathering, and generation of configuration files for headless operation on cluster nodes for a variety of artificial life models. Facilitating all of these options requires intimate knowledge of the models which will be, one hopes, written for CocoaBugs in the future; managing this sort of knowledge in a flexible, scalable way is a significant challenge...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>CocoaBugs aims to provide a framework for user interface, statistics gathering, and generation of configuration files for headless operation on cluster nodes for a variety of artificial life models. Facilitating all of these options requires intimate knowledge of the models which will be, one hopes, written for CocoaBugs in the future; managing this sort of knowledge in a flexible, scalable way is a significant challenge.</p>

<p>Currently, the codebase is centered mostly around the Packard Bugs model. In fact, more than three-quarters of the source files for CocoaBugs are for Packard's model: many views, a few controllers, tons of models. The remaining source files still share a fair amount of coupling with the Packard Bugs model.</p>

<p>Some of this has already been factored out. For example, the viewing and generation of statistics in general is managed by a StatisticsController class, which manages a StatisticsView. The StatisticsController can keep track of changing values from almost any other object, aided by Cocoa bindings and key-value observation.</p>

<p>Here's how that works. A StatisticsController has a property, the 'source', which can be any object at all. Once this property is set, the app controller can send the statistics controller a message to register for a key path with a certain name, for example,</p>

<pre><code>[myStatsController registerForPath:@"population"
                              name:@"World Population"];
</code></pre>

<p>In the code for this method, the stats controller sets up a new StatisticsView, and creates a StatisticsData object to hold the collated statistics, keeping track of the specified object with the string name. It then adds itself as an observer for the specified key path:</p>

<pre><code>[source addObserver:self
         forKeyPath:path
            options:NSKeyValueObservingOptionNew
            context:NULL];
</code></pre>

<p>Now, whenever the value referenced by the key path changes, our statistics controller is notified of the change:</p>

<pre><code>- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
  for (NSString *key in stats) {
    if ([keyPath isEqual:key]) {
      [[stats objectForKey:keyPath] addDataSet:[change objectForKey:NSKeyValueChangeNewKey]];
    }
  }
}
</code></pre>

<p>On the model side, we define another class (called WorldStatistics for the Packard Bugs model) which will serve as the data source for the statistics controller. This object knows about the Packard Bugs world, and periodically collects new statistics. It keeps track of which statistics are relevant to the current model:</p>

<pre><code>- (NSDictionary *)descriptions;
{
  return [NSDictionary dictionaryWithObjectsAndKeys:
          @"Population",      @"population",
          @"Births (total)",  @"births",
          @"Deaths (total)",  @"deaths",
          @"Average age",     @"averageAge",
          @"Mortality age",   @"mortalityAge",
          @"Gene survival",   @"geneSurvival", nil];
}
</code></pre>

<p>The app controller can ask the CocoaBugs controller for an instance of its statistics object, get these descriptions, and tell its statistics controller to listen for changes to those values. In the Packard Bugs statistics collector object, we have a single method that collects the relevant statistics:</p>

<pre><code>- (void)updateStatistics;
{
  // population
  self.population = [NSSet setWithObject:[NSNumber numberWithInt:[world.bugs count]]];

  // births
  self.births = [NSSet setWithObject:[NSNumber numberWithInt:[world.maternity count]]];
...
}
</code></pre>

<p>When this method is called and the properties are updated, the statistics controller is notified of the changes through key-value observation and updates the data models and views properly. This gives a passable, model-independent way of keeping track of model-dependent statistics.</p>

<p>However, a few limitations are already obvious. Note especially that the observed value is expected to be an NSSet of NSNumbers. This makes the statistics nice and flexible---we can have many-valued statistics---but it introduces some suboptimal overhead for the common case of keeping track of single data points like population or birth rate.</p>

<p>Moreover, there's no way to chart more exotic statistics: for example, the population variation graph for the Packard Bugs model must be handled entirely within its module, since there is no way to register for statistics other than time-based scatter plots.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="bugstats.png" src="http://bugs.doormouse.org/blog/images/bugstats.png" width="234" height="273" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span></p>

<p>Keeping all statistics data as an NSSet was necessary to give the statistics module whatever flexibility it has now, but to allow these modifications we need to go beyond the current method of statistics configuration.</p>

<p>And of course, statistics are only one of the many model-specific options that need to be managed by our general framework. Letting the app controller know what kinds of statistics to expect from a model is a very similar problem to letting it know what the configuration options for the model are, what kind of view to prepare for the model, and similar issues.</p>

<p>We'd like to find a system that is flexible enough to allow a variety of statistics options, and hopefully one that could be extended to allow the management of configuration data beyond raw statistics as well.</p>

<p>Next time, an introduction to .plists, and a possible way out of this jam.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Back from WWDC</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/06/back-from-wwdc.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.148</id>

    <published>2008-06-18T23:00:03Z</published>
    <updated>2008-06-18T23:03:25Z</updated>

    <summary>Time to hunker down on the bugs...</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[<p>WWDC was amazing. The sessions were more helpful than I had envisioned, the <a href="http://www.apple.com/macosx/snowleopard/">new omg super-secret technologies</a> are pretty damn amazing (nice that Macheads will still be able to boast about our speed advantages even after ditching PowerPC), and the Barenaked Ladies rocked the house.</p>

<p>After a few days wrestling with WindowMaker and GNUstep, and feeling like I am making very little progress indeed, I'm going to bear down and focus on transitioning CocoaBugs to being manually memory-managed. Then I'll be able to approach GNUstep with a clear head and code that, theoretically, will Just Work. (Well, after I remove all the @properties as well, anyway.) Fun!</p>

<p>Watch this space for more...</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Welcome!</title>
    <link rel="alternate" type="text/html" href="http://bugs.doormouse.org/blog/2008/05/welcome.html" />
    <id>tag:bugs.doormouse.org,2008:/blog//3.146</id>

    <published>2008-05-23T01:40:35Z</published>
    <updated>2008-05-23T19:37:45Z</updated>

    <summary>This is my summer of code blog. There are many like it, but this one is mine.</summary>
    <author>
        <name>devin</name>
        <uri>http://doormouse.org/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://bugs.doormouse.org/blog/">
        <![CDATA[This is my summer of code blog. There are many like it, but this one is mine. Here I'll be posting regular updates as to my progress with the CocoaBugs project. My major goals are listed in the top-right. Mainly, my goals are to port the current CocoaBugs codebase to GNUStep, while retaining a nice GUI, and moving from a single-model simulator to a plug-innable ALife framework with a headless batch mode.<div><br /></div><div>Wish me luck!</div>]]>
        
    </content>
</entry>

</feed>
