<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tao Effect Blog &#187; Programming</title>
	<atom:link href="http://www.taoeffect.com/blog/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.taoeffect.com/blog</link>
	<description>Notice the Tao Effects...</description>
	<lastBuildDate>Sun, 04 Jul 2010 02:40:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>The Ultimate Test Machine Saga</title>
		<link>http://www.taoeffect.com/blog/2010/06/the-ultimate-test-machine-saga/</link>
		<comments>http://www.taoeffect.com/blog/2010/06/the-ultimate-test-machine-saga/#comments</comments>
		<pubDate>Mon, 14 Jun 2010 06:46:49 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[greg]]></category>
		<category><![CDATA[macbook pro]]></category>
		<category><![CDATA[pain]]></category>
		<category><![CDATA[quad-boot]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=2129</guid>
		<description><![CDATA[So, you want to quad-boot your Mac? What could possibly go wrong? This post explores that question. Motivation After upgrading to the latest Unibody, I decided to turn my old MacBook Pro into the ultimate testing environment. My goal was to be able to test and develop software for Tiger, Leopard, Snow Leopard, Windows XP, [...]]]></description>
			<content:encoded><![CDATA[<p><center>
<div class="img"><a href="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/QuadBootingMac.jpg" class="fancybox"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/QuadBootingMac_thumb.jpg" alt="Quad-Booting Mac" title="Quad-Booting Mac" width="500" height="375" class="alignnone size-full wp-image-2197" /></a></div>
<p></center></p>
<p>So, you want to quad-boot your Mac? What could possibly go wrong?</p>
<p>This post explores that question.</p>
<h4>Motivation</h4>
<p>After upgrading to the latest Unibody, <a href="http://twitter.com/taoeffect/status/15895736075" target="_blank">I decided</a> to turn my old MacBook Pro into the ultimate testing environment. My goal was to be able to test and develop software for Tiger, Leopard, Snow Leopard, Windows XP, and possibly other operating systems in the future (Windows 7, Ubuntu, etc., although that might require <a href="http://www.gnu.org/software/grub/">Grub</a>).</p>
<h4>Setting Up The Partitions</h4>
<p>I originally thought this entire process would be a simple matter of creating partitions and installing each OS on its respective partition (Hah!). The plan was to use iPartition to create this setup without erasing my Snow Leopard install:</p>
<p><center><a href="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/PerfectTestMachine.png" class="fancybox"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/PerfectTestMachine_thumb.png" alt="Perfect Test Machine" title="Perfect Test Machine" width="500" height="380" class="alignnone size-full wp-image-2198"  /></a></center></p>
<p>To do this, I had to first run iDefrag (also made by <a href="http://www.coriolis-systems.com/" target="_blank">Coriolis Systems</a>) to compact the Snow Leopard install. Then I could non-destructively resize its partition and add the rest.</p>
<p>iPartition wasn&#8217;t able to create an NTFS partition so I left the Windows partition unformatted, everything else was formatted as HFS+, journaled.</p>
<p>I had saved a Windows install using <a href="http://www.twocanoes.com/winclone/">Winclone</a>, so I went to try to restore that. That failed because Winclone needs the partition to be formatted first.</p>
<p>I tried using Boot Camp Assistant (BCA) to create the NTFS partition, but BCA greeted me with this error (for the Googlers): &#8220;The startup disk cannot be partitioned or restored to a single partition.&#8221;</p>
<p>To get around this error you probably <i style="color:inherit">could</i> use iPartition to create a single HFS+ partition and install Snow Leopard on it. You would need to use iPartition because iPartition lets you create partitions while leaving free space on the drive, and remember, we need that space to create additional partitions for the other operating systems. Disk Utility cannot leave &#8220;unpartitioned space&#8221; on the drive, and therefore you&#8217;d end up creating more than one partition before running BCA, which would then refuse to do its thing.</p>
<p>I went a different route though, as I discovered that by installing <a href="http://macntfs-3g.blogspot.com/">NTFS-3G</a> (the free Open Source version), I could create NTFS partitions using Disk Utility. So I partitioned the entire drive, this time using Disk Utility, and was able to successfully restore Windows to the NTFS partition using Winclone.</p>
<p>That was the easy part though.</p>
<h4>Fragile Windows</h4>
<p>Restoring Windows is one thing, getting it to boot is another. Upon rebooting to check the XP install, I was greeted with a black screen and error message along the lines of &#8220;No bootable device available.&#8221;</p>
<p>After searching Google I came across <a href="http://www.macosxhints.com/article.php?story=20090807033320433">this hint</a> on how to triple-boot your system. The comments section were particularly helpful, and led me to investigate the <b><span class="code">boot.ini</span></b> file as a possible source of the problem.</p>
<p>The <span class="code">boot.ini</span> file, for some reason, specifies what partition number it&#8217;s located on. My Windows partition was in the wrong location, and it didn&#8217;t like that. So I followed their suggestions and edited the file using emacs, and played around with the number. I tried every single number between 1 and 6, and even zero (out of desperation), none would satisfy Windows.</p>
<p>At some later point, after much formatting and reinstalling, I actually got Windows to boot, only to be greeted by a blue screen instead of a black screen, which flashed too quickly for me to read and then the computer restarted itself.</p>
<p>Although I don&#8217;t have a complete list of my Googles during this time, here&#8217;s what I was able to dig up from Firefox&#8217;s history, hopefully it will save a fellow Googler or two:</p>
<ul>
<li>chkdsk &#8220;volume appears to contain&#8221;</li>
<li>&#8220;windows could not start&#8221; hal.dll</li>
<li>windows xp recovery console</li>
<li>&#8220;no bootable device&#8221; boot.ini bootcamp</li>
<li>boot camp UNMOUNTABLE_BOOT_VOLUME</li>
<li>&#8220;there is no operating system installed in this virtual machine&#8221; <i>(That&#8217;s from Parallels)</i></li>
</ul>
<h4>The &#8220;Right&#8221; Partition</h4>
<p>Here&#8217;s what I now know. Editing <span class="code">boot.ini</span> may or may not work. In my case (with Windows XP) it definitely did not. Prior to embarking on this journey, you need to decide ahead of time what to install on the first two partitions, because the third has to be Windows. In Disk Utility, partitions start from the top:</p>
<p><center><a href="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/partitions.png" class="fancybox"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/partitions_thumb.png" alt="Disk Utility Partition Map" title="Disk Utility Partition Map" width="500" height="440" class="alignnone size-full wp-image-2193" /></a></center></p>
<p>I&#8217;m <i style="color:inherit">pretty sure</i> Windows must be installed on the third partition. It&#8217;s either that or the second one. For me right now, the third partition has done the trick.</p>
<p>Now, with a working WIndows install, I know how to verify the number in the <span class="code">boot.ini</span> file. It does in fact correspond to the partition number as specified in the output of <span class="code">diskutil list</span>, and/or <span class="code">df</span>. It&#8217;s one greater than the number you&#8217;d expect if you were just going by Disk Utility&#8217;s GUI. Here&#8217;s the output from the quad-booting laptop as it is now, showing it as partition #4:</p>
<pre class="code">Last login: Sun Jun 13 19:22:13 on console
Macintosh:~ gslepak$ diskutil list
/dev/disk0
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *200.0 GB   disk0
   1:                        EFI                         209.7 MB   disk0s1
   2:                  Apple_HFS Snow Leopard            49.7 GB    disk0s2
   3:                  Apple_HFS Leopard                 32.6 GB    disk0s3
   4:       Microsoft Basic Data Windows                 29.2 GB    disk0s4
   5:                  Apple_HFS Tiger                   20.6 GB    disk0s5
Macintosh:~ gslepak$ df
Filesystem    512-blocks     Used Available Capacity  Mounted on
/dev/disk0s2    97069312 23384096  73173216    25%    /
devfs                218      218         0   100%    /dev
map -hosts             0        0         0   100%    /net
map auto_home          0        0         0   100%    /home
/dev/disk0s3    63741456 24106640  39634816    38%    /Volumes/Leopard
/dev/disk0s4    57012216 29356408  27655808    52%    /Volumes/Windows
/dev/disk0s5    40174016 15283088  24890928    39%    /Volumes/Tiger
</pre>
<h4>Stubborn Tiger</h4>
<p>Not to be outdone by its Redmond counterpart, Mac OS 10.4 Tiger turned out to be even more difficult to install.</p>
<p>First, the install disk that came with the computer (which had 10.4.9) refused to be recognized. It spun for a little while and was then spit out. So I inserted it into my PowerMac figuring I could just install over Target Disk Mode, but it refused to run because Apple watermarks these DVDs so that they only work on the exact same kind of computer.</p>
<p>Fortunately, I had another Tiger install disk that did work with any Mac. It was only after the installation finished (over Target Disk Mode, again), that I realized it was a PPC-only install, causing the Intel laptop to kernel panic on boot.</p>
<p>Feeling defeated, I went for a jog, during which I realized that I could insert the Intel install disk into my Unibody MacBook Pro, copy it onto an external hard disk, and boot off of that, thereby bypassing the flaky SuperDrive on the old MacBook Pro.</p>
<p>That outta do it, right?</p>
<p><center><a href="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/TigerStripes.jpg" class="fancybox"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/TigerStripes_thumb.jpg" alt="Tiger&#039;s Stripes" title="Tiger&#039;s Stripes" width="500" height="375" class="alignnone size-full wp-image-2199" /></a></center></p>
<p>And it did! Now I just had to figure out what to do about the crazy blue and black stripes on the screen that made it impossible to see the installer.</p>
<p>You see, this laptop, like most of its kind, was affected by the <a href="http://forums.macrumors.com/showthread.php?t=515067">infamous NVIDIA 8600GT</a> bug that completely wiped out its display capabilities. Apple <a href="/blog/2008/11/back-up-and-running/">kindly replaced</a> the logic board but, in doing so, apparently killed its compatibility with Tiger.</p>
<p>You would think that by this point any sane person would have called it a day, but it was far too late for me. My OCD was in overdrive, and I had become sort of obsessed with solving this problem. Failure was not an option&#8230; not yet at least.</p>
<p><a href="http://support.apple.com/kb/HT1492">Verbose mode</a> showed the following error:</p>
<pre class="code">GFX0 matching specific fails</pre>
<p>Google wasn&#8217;t very helpful here unfortunately, but I figured that there was a missing or outdated graphics driver. So I spent some time copying and replacing kernel extensions from my Leopard install (which had finished without problems) into the Tiger installation drive. This took a rather long time, as each time I changed a kernel extension I had to reboot to see if the fix took. I had to replace them one at a time so as to avoid potentially compounding the problem (as kernel extensions have dependencies).</p>
<p><i>Sidenote: If you ever find yourself switching out kernel extensions, don&#8217;t forget to delete the cache files &#8216;Extensions.mkext&#8217; and &#8216;Extensions.kextcache&#8217; each time you do. These files may or may not be present in the /System/Library folder, depending on the OS version.</i></p>
<p>Eventually I realized this was stupid, because I could simply run the OS install by running the OSInstall.mpkg from within Snow Leopard:</p>
<p><center><a href="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/OSInstall.png" class="fancybox"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/OSInstall_thumb.png" alt="OSInstall.mpkg" title="OSInstall.mpkg" width="500" height="274" class="alignnone size-full wp-image-2200" /></a></center></p>
<p>The installer ran (and hung at the end, of course) but it looked like it had installed everything that was necessary so I rebooted again from the Tiger disk.</p>
<p>I should mention that sometimes the disks that I needed to boot from did not appear in the Startup Disk preference pane, despite being bootable. I got around that by running the <span class="code">bless</span> command on the volume:</p>
<pre class="code">sudo bless --mount /Volumes/Tiger --setBoot --nextonly</pre>
<p>I booted into Tiger and again was greeted with its unreadable blue stripes, and by now the all too familiar setup theme music. Curses!</p>
<p>I decided to install the 10.4.11 Combo Update from Snow Leopard, thinking it might contain the proper drivers. The download link on Apple&#8217;s site was broken, but by this point the random problems no longer surprised me. After some searching I finally found <a href="http://supportdownload.apple.com/download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/Mac_OS_X/downloads/061-4048.20071114.6Gn4g/MacOSXUpdCombo10.4.11Intel.dmg">a working link</a> to it. Too bad though, the update did not fix the problem.</p>
<p>It then dawned upon me that this was all a test. God was testing me, to see how badly I wanted to install the outdated operating system, and whether I really did possess the geek-credentials I claimed to have.</p>
<p>So I went back to the old plan of replacing kernel extensions.</p>
<p>I copied a bunch of extensions over from Leopard that I thought might fix the problem without causing too many dependency issues. While that did get rid of the error message, and Tiger no longer sported blue and black stripes, instead, I saw only the black and white text of the verbose screen while the Tiger setup music played in the background, taunting me.</p>
<p>I proceeded to replace the kernel extensions with the originals, one-by-one, hoping to find the one that was responsible for the missing error message. After what had to be at least an hour I finally noticed it: the GFX0 error message was back, and it was after I had replaced <span class="code">NVDAResman.kext</span> with its original.</p>
<p>Intrigued, I restored the entire Extensions folder back to its original state and replaced <i style="color:inherit">just</i> <span class="code">NVDAResman.kext</span>.</p>
<p><center><a href="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/TigerInstallSuccess.jpg" class="fancybox"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/TigerInstallSuccess_thumb.jpg" alt="Tiger Install Success!" title="Tiger Install Success!" width="500" height="375" class="alignnone size-full wp-image-2201" /></a></center></p>
<p><b>Success!!</b></p>
<p><i>Almost!</i> There was one loose-end left to fix. After logging into my account on Tiger, I got a couple of error messages complaining about <span class="code">NVDANV50Hal.kext</span> and <span class="code">GeForce.kext</span> not loading properly. Simply removing them from the <span class="code">/System/Library/Extensions</span> did the trick, with no noticeable ill effects (I tried replacing them with the ones from the Leopard install, but that didn&#8217;t work).</p>
<p>As a finishing touch, I used iPartition to shrink the Tiger partition. This way I won&#8217;t have to run iDefrag on it if I decide to install additional operating systems in the future (like 10.7). Here&#8217;s how it looks in Disk Utility:</p>
<p><center><a href="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/FinalPartitionMap.png" class="fancybox"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/06/FinalPartitionMap_thumb.png" alt="Final Partition Map" title="Final Partition Map" width="500" height="440" class="alignnone size-full wp-image-2202" /></a></center></p>
<p>Hopefully this post will save someone a headache, or two. <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2010/06/the-ultimate-test-machine-saga/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dear Apple: The iPhone deserves better SDK terms</title>
		<link>http://www.taoeffect.com/blog/2010/04/dear-apple-the-iphone-deserves-a-better-sdk/</link>
		<comments>http://www.taoeffect.com/blog/2010/04/dear-apple-the-iphone-deserves-a-better-sdk/#comments</comments>
		<pubDate>Fri, 09 Apr 2010 17:02:57 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[apple]]></category>
		<category><![CDATA[FuckingAppStore]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[greg]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=1942</guid>
		<description><![CDATA[Outrage over this little clause in the new iPhone developer SDK terms is erupting all over the internet: 3.3.1 — Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs. Applications must be originally written in Objective-C, C, C++, or JavaScript as executed by [...]]]></description>
			<content:encoded><![CDATA[<p>Outrage over this little clause in the new iPhone developer SDK terms is <a href="http://joeberkovitz.com/blog/2010/04/08/apple-takes-stance-on-consciousness/">erupting</a> <a href="http://whydoeseverythingsuck.com/2010/04/steve-jobs-has-just-gone-mad.html">all</a> <a href="http://fulldisclojure.blogspot.com/2010/04/steve-jobs-just-ruined-iphone-for.html">over</a> <a href="http://redth.info/2010/04/09/is-monotouch-now-dead-in-the-water-what-does-apples-new-iphone-developer-agreement-mean/">the</a> <a href="http://blog.joa-ebert.com/2010/04/09/what-apple-just-did/">internet</a>:</p>
<blockquote><p>3.3.1 — Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs. Applications must be originally written in Objective-C, C, C++, or JavaScript as executed by the iPhone OS WebKit engine, and only code written in C, C++, and Objective-C may compile and directly link against the Documented APIs (e.g., Applications that link to Documented APIs through an intermediary translation or compatibility layer or tool are prohibited).</p></blockquote>
<p>And rightly so.</p>
<p>On our <a href="/about">About page</a> we explain why we develop <a href="/espionage">software</a> for the Mac:</p>
<blockquote><p style="text-align:center">We believe that Apple has created an <a href="http://www.apple.com/macosx/">environment</a> where great software can really thrive.</p>
</blockquote>
<p>I still feel this way about the Mac, but I no longer consider the iPhone or the iPad worthy of such sentiment because of the draconian terms under which one must operate to develop for those platforms.</p>
<p>What Apple&#8217;s engineers have done with the iPhone is amazing. They&#8217;ve simply outdone themselves when it comes to the quality of both the software and the hardware. However, I no longer think Apple can continue to honestly claim that they have the best phone around. Steve Jobs and Apple&#8217;s legal department have taken a figurative dump on their hard work with these insane restrictions, and that creates an foul odor that stains the product as a whole.</p>
<h4>Missing Applications</h4>
<p>The new rules, interpreted as written, ban all kinds of applications written by great folks who have put in countless hours of work developing for this platform.</p>
<p>Games developed using the great <a href="http://unity3d.com/unity/">Unity3D</a> engine are <i>not</i> &#8220;originally written&#8221; in Objective-C, C, or C++.</p>
<p>The incredible work that <a href="http://jlongster.com/about/">James Long</a> put into creating what is probably the first-ever <a href="http://jlongster.com/blog/2010/04/05/farmageddon-available/">OpenGL game written in Scheme on the App Store</a>, is now thrown <a href="http://jlongster.com/blog/2010/04/09/scheme-dead-iphone/">into question</a>.</p>
<p>With these terms, Apple is going against its own <b>Think Different</b> model, destroying creativity itself through the enforcement of a monoculture of developer tools. They are effectively saying that you can be creative, <i>so long as you&#8217;re creative our way</i>, an absurdity known in psychology as a <a href="http://en.wikipedia.org/wiki/Double_bind">double bind</a>.</p>
<h4>Developers Running Away</h4>
<p>The SDK terms are not just insulting, they&#8217;re bad business. Great developers like Tim Bray <a href="http://techcrunch.com/2010/03/15/tim-bray-android-google-iphone/">are forsaking the iPhone platform out of disgust</a> and running to Google&#8217;s Android platform. Dan Grigsby of Mobile Orchard <a href="http://www.mobileorchard.com/goodbye/">just announced</a> they&#8217;re abandoning iPhone development because of these restrictions.</p>
<p>Despite my familiarity with Apple&#8217;s tools and the language Apple insists developers use, at the present time I can&#8217;t envision myself writing an app for the App Store, because in clicking that Agree button on the license terms I suddenly find myself feeling like an infant, as though I can no longer be trusted to make basic decisions and must therefore be locked in a crib surrounded by child-proof toys and bars.</p>
<p>For companies like Google, all of this should be good news, because despite its shortcomings, Android&#8217;s relatively open platform is starting to look far more inviting.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2010/04/dear-apple-the-iphone-deserves-a-better-sdk/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Easy Cocoa Setup Assistants with TESetupAssistant</title>
		<link>http://www.taoeffect.com/blog/2010/01/easy-cocoa-setup-assistants-with-tesetupassistant/</link>
		<comments>http://www.taoeffect.com/blog/2010/01/easy-cocoa-setup-assistants-with-tesetupassistant/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 02:25:59 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Free Stuff]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[greg]]></category>
		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=1766</guid>
		<description><![CDATA[Setup assistants can be a great tool when you need to guide users through a series of steps. TESetupAssistant was born during my work on the 2.0 update to Espionage, when I discovered that many of its UI elements could stand to benefit from a generic setup assistant class. The gallery below shows some of [...]]]></description>
			<content:encoded><![CDATA[<p>Setup assistants can be a great tool when you need to guide users through a series of steps.</p>
<p><b>TESetupAssistant</b> was born during my work on the <a href="/blog/2009/02/espionage-20-released/">2.0 update</a> to <a href="/espionage">Espionage</a>, when I discovered that many of its UI elements could stand to benefit from a generic setup assistant class.</p>
<p>The gallery below shows some of the places in Espionage where we use TESetupAssisant, illustrating its versatility:</p>
<div class="imageGallery" style="background-color:black">
<ul style="width:500px">
<li><a rel="imageGallery" href="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/keychain.png" title="Switching keychains"><img style="margin-top:20px" src="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/keychain_thumb.png"/></a></li>
<li><a rel="imageGallery" title="Encrypting application data" href="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/apptemplates.png"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/apptemplates_thumb.png" /></a></li>
<li class="right"><a rel="imageGallery" title="Installing Espionage itself" href="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/install.png"><img style="margin-top:25px" src="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/install_thumb.png" /></a></li>
</ul>
<div class="clear"></div>
</div>
<p>You can create these sorts of UIs very quickly and use them wherever the user needs to complete a series of steps, or even a single step (as shown in the first image above). Here&#8217;s a basic overview of it:</p>
<p><center><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/TESetupAssistant.png" /></center></p>
<p>There are two main classes: <B>TESetupAssistant</b> and <B>TEBaseAssistant</b>. TESetupAssistant is associated with a nib file that determines the overall layout. It manages a one or more assistants, each of which inherit from TEBaseAssistant. Each TEBaseAssistant subclass has its own nib file, usually just containing a single NSView container object.</p>
<h3>Example of a Modal Assistant</h3>
<p>Here&#8217;s an example of a very simple assistant using the minified UI and running modally:</p>
<p><center><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/simple_assistant.png"/></center></p>
<p>And here is all the code needed to create it:</p>
<pre class="code">
<span class="source source_objc"><span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include">#<span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c">import</span> <span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">&lt;</span>Cocoa/Cocoa.h<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">&gt;</span></span></span>
<span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include">#<span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c">import</span> <span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>TESetupAssistant.h<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span></span>

<span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">MiniAssistant</span> <span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc">:</span> <span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc">TEBaseAssistant</span><span class="meta meta_divider meta_divider_objc"> </span><span class="meta meta_scope meta_scope_interface meta_scope_interface_objc">{
    <span class="storage storage_type storage_type_objc">IBOutlet</span> <span class="support support_class support_class_cocoa">NSTextField</span> *textField;
}
</span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span>

<span class="meta meta_implementation meta_implementation_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>implementation</span> <span class="entity entity_name entity_name_type entity_name_type_objc">MiniAssistant</span>
<span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="support support_class support_class_cocoa">NSArray</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">orderedSteps</span></span>
</span>{
    <span class="keyword keyword_control keyword_control_c">return</span> <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="support support_class support_class_cocoa">NSArray</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">arrayWithObject<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>Mini Step<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
}
<span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">start</span></span>
</span>{
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>controller <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">nextButton</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">setTitle<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>Finish<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>textField <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">setStringValue<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>NSSTR_FMT(
        <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Hi there! I'm a mini-assistant <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%s</span>running modally!<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>,
        <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>controller <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">modal</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> ? <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span> : <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>not <span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>)
    </span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
}
</span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span>

<span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> To run it modally is just 4 lines of code (somewhere):
</span>
TESetupAssistant *sa = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>TESetupAssistant <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">alloc</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">initMini</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">autorelease</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>sa <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">setModal<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="constant constant_language constant_language_objc">YES</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>sa <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">addAssistant<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>MiniAssistant <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">assistant</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>sa <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">run</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;</span>
</pre>
<p>Notice that we don&#8217;t even need to load the nib file. That&#8217;s because our nib file is named after our assitant (MiniAssistant.nib). You can of course override the <span class="code">-assistantNib</span> method to specify a different one, but that illustrates one key aspect of TESetupAssistant, and that is that there are sensible defaults for almost everything, allowing you to quickly throw together these kinds of interfaces.</p>
<h3>Get It On Bitbucket</h3>
<p>I&#8217;m releasing TESetupAssistant as open source under a liberal license (just an attribution is asked for), and I&#8217;ve included a little demo app to help you hit the ground running. You can <a href="http://bitbucket.org/taoeffect/tesetupassistant/downloads/">download</a> it <a href="http://bitbucket.org/taoeffect/tesetupassistant/overview/">on bitbucket</a>.</p>
<p>If you use it in your application I&#8217;d love to know! Shoot us an email or post a comment below and I&#8217;ll place a link here to your app.</p>
<p>Enjoy! <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><i style="color:inherit">You can follow me on twitter <a href="http://twitter.com/taoeffect">here</a>.</i></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2010/01/easy-cocoa-setup-assistants-with-tesetupassistant/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How newLISP Took My Breath (And Syntax) Away</title>
		<link>http://www.taoeffect.com/blog/2010/01/how-newlisp-took-my-breath-and-syntax-away/</link>
		<comments>http://www.taoeffect.com/blog/2010/01/how-newlisp-took-my-breath-and-syntax-away/#comments</comments>
		<pubDate>Fri, 08 Jan 2010 15:34:34 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[newLISP]]></category>
		<category><![CDATA[greg]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=644</guid>
		<description><![CDATA[A few years ago, a little-known language called newLISP completely changed my understanding of what &#8220;good&#8221; programming languages look like. Why newLISP? Before saying another word, I&#8217;d like to address the question that some of my LISP-familiar readers may be asking right now: Why newLISP? Why not Clojure, Scheme, or Common LISP? The answer is [...]]]></description>
			<content:encoded><![CDATA[<p>A few years ago, a little-known language called <b>newLISP</b> completely changed my understanding of what &#8220;good&#8221; programming languages look like.</p>
<h4>Why newLISP?</h4>
<p>Before saying another word, I&#8217;d like to address the question that some of my LISP-familiar readers may be asking right now: <b>Why newLISP? Why not Clojure, Scheme, or Common LISP?</b></p>
<p>The answer is that after evaluating these dialects of LISP, I&#8217;ve come to the conclusion that <i>newLISP has several important advantages over other LISPs.</i></p>
<p>Today, unfortunately, whenever someone mentions newLISP on an online forum frequented by adherents of another LISP, an almost clan-like flame war will erupt. An adherent of one particular dialect, usually someone who has never used newLISP, will shout obscenities such as, <b>&#8220;newLISP goes <i>back</i> on just about every advancement made by LISPs&#8221;</b>, or <b>&#8220;dynamic scope is evil!&#8221;</b></p>
<p>The historical context out of which these sentiments are born is mostly unknown to those observing the debate. As signal gives way to noise, the discussion collapses, the melee disperses, and the bystanders go back to sipping their Java and eating their Pythons.</p>
<p>It is fortunate, I think, that my introduction to the language did not sprout out of one of these battles. It was, for the most part, largely unbiased.</p>
<h4>Something called LISP</h4>
<p>While attending the University of Florida, I had signed up for a course on artificial intelligence. Our professor predictably introduced the class to a programming language called <a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)">LISP</a>.</p>
<p>Up to that point in time my knowledge of LISP consisted of the usual hearsay and mantra of those unfamiliar with the language:</p>
<blockquote><p style="text-align:center">&#8220;People who like it are crazy zealots who think they&#8217;re superior to everyone!&#8221;<br />
&#8220;It&#8217;s mainly used for artificial intelligence stuff.&#8221;<br />
&#8220;No one uses it for practical purposes.&#8221;<br />
&#8220;It&#8217;s mainly used as a research language.&#8221;<br />
&#8220;It stands for &#8216;Lots-of-Irritating-Silly-Parenthesis&#8217;. Haha!&#8221;
</p>
</blockquote>
<p>You get the idea. I did not have a clue as to what it was, but I was excited to finally be forced into the position of having to find out. My grade depended on it, after all.</p>
<p>What I discovered was that LISP did in fact live up to its reputation of zealot-inducing awesomeness. Simply being exposed to some of the basic concepts and philosophies of LISP had an immediate and positive impact on my abilities as a programmer.</p>
<h4>Syntax: Programmer Enemy #1</h4>
<p>LISP&#8217;s <a href="http://www.taoeffect.com/blog/wp-content/uploads/2009/12/LISP-in-a-nutshell2.gif" class="fancybox">relative lack of syntax</a> was perhaps the greatest insight, for I immediately felt as though a great weight had disappeared. I realized that it was syntax that was at the root of most programming errors. It was syntax that created a subconscious burden that I had simply been unaware of; causing errors, bugs, and making it difficult to simply turn my thoughts into code. Despite having many years of experience with C-based languages, and being intimately familiar with their syntax, I realized that it was nevertheless a totally unnecessary burden that was slowing me, and everyone else, down.</p>
<blockquote class="oneliner">
<p style="font-style:italic">This is one great advantage of Lisp-like languages: They have very few ways of forming compound expressions, and almost no syntactic structure. . . . After a short time we forget about syntactic details of the language (because there are none) and get on with the real issues.</p>
<p class="author">&mdash;Abelson and Sussman</p>
</blockquote>
<p>It&#8217;s not just the size of the syntax that matters, it&#8217;s what you can do with it. What requires layers of special syntax in languages like PHP, Python and Ruby, LISP can do with its basic concepts of lists, functions and symbols. It can do everything those languages can do, in a more elegant fashion, and still have enough tricks left up its sleeve to accomplish feats that are simply <i>not possible</i> in other languages.</p>
<h4>Common LISP: A Series of Unfortunate Mistakes</h4>
<p>Despite all of these exciting discoveries I still had an uneasy feeling.</p>
<p>Common LISP (CL) was a great departure from what I had known previously, but it reeked of antiquity, and worse, its syntax simply wasn&#8217;t very well thought out. The &#8220;Zen-like&#8221; perfection that it seemed to be yearning for was missing. It was a feeling that Mac users are all too familiar with: <b>There were too many buttons, and most of them were unnecessary.</b></p>
<p><center><img src="http://www.taoeffect.com/blog/wp-content/uploads/2010/01/CL-in-a-nutshell.gif" alt="Common LISP Syntax in a Nutshell" title="Common LISP Syntax" width="500" height="320" class="alignnone size-full wp-image-1498" /></center></p>
<p>Compared to C++, that&#8217;s fantastic. Then again, compared to C++, <i>most</i> languages appear favorable. Having had a taste of the liberty offered by the drop in syntax from C/C++/Java to CL, I did not see <i style="color:inherit">why</i> all of this syntax was necessary, and indeed, most of it wasn&#8217;t.</p>
<p>Every little piece of syntax that&#8217;s introduced into a language adds to the programmer&#8217;s mental burden, be he conscious of it or not. I was not prepared to spend the effort learning Common LISP if a better alternative could be found.</p>
<div class="box" style="margin-bottom:20px">
<h4>What do you mean by &#8220;syntax&#8221;?</h4>
<p>You may object at my inclusion of the functions <span class="code">defvar</span>, <span class="code">=</span>, <span class="code">eq</span>, <span class="code">eql</span>, etc. as they are <i>functions</i>. I include them because they constitute low-level functionality that cannot be expressed in the syntax of LISP itself. In other words, the functions <span class="code">=</span> and <span class="code">eq</span> are low-level primitives that must be defined in the language that LISP itself is implemented in, and their meaning and usage cannot be deduced from any other existing LISP syntax.</p>
<p class="last">Consider PHP&#8217;s <span class="code">!=</span> and <span class="code">!==</span>, they are both <i>operators</i> and are used in the same way, yet that doesn&#8217;t tell you anything about what the difference between them is. There&#8217;s no way to deduce their meaning from the existing semantics of the language and thus they each represent new syntax that must be learned.</p>
</div>
<h4>How I Discovered newLISP</h4>
<p>The professor revealed to us our &#8220;major class project&#8221;: we were to implement a text-based version of the game Chainshot:</p>
<p><center>
<div class="img" style="margin-bottom:0px"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2009/12/chainshot.png" alt="Chainshot" title="Chainshot" width="282" height="305" class="alignnone size-full wp-image-1154" />
<p class="last">An implementation of Chainshot</p>
</div>
<p></center></p>
<p>Chainshot starts with a grid completely filled with colored cells. Your goal is to clear the board and you do this by clicking on each cell. If the cell has any adjacent cells of the same color, they all disappear. The effect spreads to include all of the cells adjacent to those, and so on. Cells then drop down to fill in the gap left by the vanished group. If an entire column disappears then all cells to the right of it move left to fill it in. There&#8217;s a wonderful and free implementation of this for OS X called <a href="http://www.macupdate.com/info.php/id/24493/otis">Otis</a>.</p>
<p>For the midterm we were to make a version of this playable by a human, and for the final we had to write an AI to play the game.</p>
<p><i>&#8220;One more thing&#8230;&#8221; he said, &#8220;If you do it in LISP, you&#8217;ll get a 10% bonus.&#8221;</i></p>
<p>The problem though was most of the lectures focused on various algorithms and theory for doing AI. Those who wanted the 10% bonus would have to teach themselves the language.</p>
<p>Most students chose to forsake the bonus in favor of using a language that they were already familiar with, and like most students I had very little time, so I was partial to that sentiment. However, I decided to do a Google search to see if I could find a Common LISP alternative that was more appetizing.</p>
<p>To my delight I found a language that seemed to check all the right boxes, and surprisingly it wasn&#8217;t <a href="http://en.wikipedia.org/wiki/Scheme_(programming_language)">Scheme</a> (although that is a wonderful language as well). Like Scheme, this language had greatly simplified Common LISP&#8217;s syntax, but at the same time it came with a standard library full of useful functions for performing modern scripting tasks, and all you needed to run it was a single tiny executable!</p>
<h3>Discovering newLISP</h3>
<p><img src="http://www.taoeffect.com/blog/wp-content/uploads/2009/12/newlisp-logo-horizontal-240x100.png" alt="newLISP" title="newLISP" width="240" height="100" class="alignright size-full wp-image-1049" style="float:right; padding-left: 10px; padding-bottom:20px" />Here is what ultimately turned me into such a fan of <a href="http://www.newlisp.org">newLISP</a>.</p>
<p>We had several months to complete the first part of the project, and the night before it was due, I did not have a <i>single part</i> of it complete. I had spent the night working on other things, and for perhaps an hour I spent some time looking over the newLISP website, reading about it.</p>
<p>The next day, approximately four hours before I was to hand in my finished, playable version of Chainshot, I sat down at a desk, put on my headphones, and proceeded to <i>simultaneously</i> learn newLISP while creating this game with it.</p>
<p>I finished in about <b>3 hours</b>, of which only about ten minutes was spent debugging. I was dumbfounded. I had discovered something new, a language that allowed me to rapidly write what, after years of C-based languages, seemed like <i>virtually &#8220;bug-free code&#8221; that just worked.</i> It was a language that I had come close to <i>mastering</i> in a matter of minutes, having never used it before! In the time I had learned newLISP and written a text-based game in it I would probably only be finishing the tutorials for Ruby or Python.</p>
<h4>newLISP&#8217;s Strengths</h4>
<p>At the beginning of this post I made the claim that newLISP has several advantages over the other LISPs. They can all be summarized as follows: <b>If you want a LISP-based scripting language, choose newLISP.</b></p>
<p>Before getting into the details let me warn:</p>
<blockquote><p style="text-align:center; font-style:normal; font-weight:bold">newLISP is <i>not</i> a general-purpose programming language.</p>
</blockquote>
<p>In the same sense that you wouldn&#8217;t use JavaScript to write an iPhone app (some <a href="http://www.nimblekit.com/">beg to differ</a>), you wouldn&#8217;t use use newLISP to write an operating system, a music player like iTunes, or a web browser like Firefox. For such endeavors I recommend without hesitation Clojure, Scheme, C, Objective-C, etc. In other words, languages geared for solving complex, low-level problems, as quickly as possible.</p>
<p>The very first sentence on newLISP&#8217;s website states (emphasis mine):</p>
<blockquote><p style="text-align:center; font-style:normal; font-weight:bold">newLISP is a Lisp-like, general-purpose <i>scripting</i> language.</p>
</blockquote>
<p>Long ago, when computers were slow, the LISP community was mercilessly mocked by their C and Assembly-wielding counterparts for the crime of being <i>too slow.</i> Ever since that time the subject of performance has been a sore spot for the LISP community from which, I dare say, it has yet to fully recover. Its focus turned towards compilation and proving to the world that it too, could be fast. As a result, few seem to have noticed the need for a general-purpose LISP focused instead on interpretation and scripting.</p>
<p>Luckily, newLISP seems to fit that role rather well. It is a general-purpose interpreted scripting language. It&#8217;s my understanding that because of how dynamic it is, it cannot even be compiled to bytecode (this does not mean it is not fast, though).</p>
<p>Without this understanding, some of its design decisions will not make sense. Why choose fexprs over macros? Why dynamic scope instead of lexical scope? Why <a href="http://www.newlisp.org/MemoryManagement.html">One-Reference-Only</a> memory management instead of garbage collection?</p>
<h4>Design and Syntax</h4>
<p>newLISP comes in a single, tiny 200+KB binary executable. Out of all the LISP derivatives I&#8217;ve tried, it is the easiest to setup, deploy, and develop for. Somehow that tiny package contains the entire language and includes functions for reading and writing files, parsing text, regular expressions, running code in parallel, over a network, and much more. For the final project I was the only person in the class to submit a fully parallelizable AI (scalable to any number of cores) to solve each grid. The only reason I did it was because I could do it without breaking a sweat. newLISP made it mind-numbingly easy, and this was before it had all the <a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-19">actor</a> and <a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-18">Cilk</a> stuff.</p>
<p>newLISP&#8217;s syntax is minimalist and well thought out. For the sake of comparison with the Common LISP syntax card, I&#8217;ve kept most of the attributes (such as font size) the same:</p>
<p><center><img src="http://www.taoeffect.com/blog/wp-content/uploads/2009/12/newLISP-in-a-nutshell2.gif" alt="newLISP in a nutshell" title="newLISP in a nutshell" width="500" height="320" class="alignnone size-full wp-image-1312" /></center></p>
<p>Functions do not need any of the <span class="code">&#038;rest</span>, <span class="code">&#038;optional</span> flags. Simply pass in variables or don&#8217;t, the parameters that don&#8217;t get anything are set to nil, and extra stuff can be accessed through the function <span class="code">(args)</span> or the symbol <span class="code">$args</span>.</p>
<p>Functions, like most other things, evaluate to themselves. You don&#8217;t need a special <span class="code">#&#8217;</span> syntax to access them. Functions are also <i>real lists</i>. This means you can get their <a href="http://www.newlisp.org/downloads/newlisp_manual.html#source">source</a> after they&#8217;ve been defined, and even <a href="http://kazimirmajorinc.blogspot.com/2009/04/crawler-tractor.html">modify them <i style="color:inherit">while they are executing</i></a>.</p>
<h4>fexprs and <span class="code" style="font-size:inherit; font-weight:inherit; font-style:inherit;">eval</span></h4>
<p>Instead of macros newLISP chose to use <a href="http://en.wikipedia.org/wiki/Fexpr">fexprs</a>, or functions that simply don&#8217;t evaluate their arguments (although to the chagrin of some, newLISP calls them macros). This decision makes sense because in an interpreted LISP, almost everything happens at runtime and there are situations where fexprs can be much faster to execute than macros. It also means that newLISP&#8217;s &#8220;macros&#8221; don&#8217;t need the special backquote syntax, making them easier to write and read.</p>
<p>You may have heard the mantra against using <span class="code">eval</span> in other languages. In newLISP, this just doesn&#8217;t apply. newLISP&#8217;s <a href="http://kazimirmajorinc.blogspot.com/2008/12/speed-of-newlisp-eval-test-v100.html">eval is faster than other LISPs</a>.</p>
<p>This has many consequences, one of which is that sometimes newLISP&#8217;s fexprs <a href="http://kazimirmajorinc.blogspot.com/2009/04/on-macro-expansion-evaluation-and.html">can be faster than compiled macros</a> in the other LISPs, but also it means that using <span class="code">eval</span> is no longer frowned upon, which opens up all sorts of coding possibilities.</p>
<h4>Equality and Memory Management</h4>
<p>Notice that there&#8217;s a single equality operator, the equals sign. newLISP can get away with this luxury because of its memory-management model, called <a href="http://www.newlisp.org/MemoryManagement.html">One-Reference-Only (ORO)</a>.</p>
<p>In short, most things are passed <i>by-value</i> and so you end up not needing all of those ridiculous comparison functions. If two things have the same value they are equal&mdash;end of story (except in the case of <a href="/blog/2009/12/introducing-objective-newlisp/">Objective newLISP</a>).</p>
<p>This is not as crazy as it sounds. Internally, newLISP passes data by reference between built-in functions and does other optimizations. You can pass data by reference through the use of <a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-3">contexts and symbols</a>, or by using <a href="/blog/2009/12/introducing-objective-newlisp/">Objective newLISP</a>. newLISP&#8217;s ORO also means repeatable code execution times; you&#8217;ll never experience &#8220;GC Hell&#8221; because there is no garbage collector.</p>
<h4>Dynamic Scope</h4>
<p>Much fuss is often made over newLISP&#8217;s use of <a href="http://en.wikipedia.org/wiki/Scope_%28programming%29#Dynamic_scoping">dynamic scope</a>. It is true, dynamic scope <i>can be dangerous!</i></p>
<p>In a similar way, <i>pointers and alcohol can be dangerous too!</i> That doesn&#8217;t mean you shouldn&#8217;t ever program in C or enjoy yourself at a party. Check for <span class="code">NULL</span>, don&#8217;t drink and drive, and beware of &#8220;free variables.&#8221;</p>
<p>Remember, newLISP is an interpreted language. Lutz Mueller, the author of newLISP, made a simple cost/benefit analysis and chose dynamic scope because it&#8217;s faster than lexical scope, and because it&#8217;s very easy to avoid the potential pitfalls of dynamic scope. Instead of this:</p>
<pre class="code"><span class="source source_newlisp"><span class="entity entity_paren entity_paren_lisp">(</span><span class="meta meta_function meta_function_lisp"><span class="storage storage_type storage_type_function-type storage_type_function-type_lisp">define</span> <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_functiondef entity_name_functiondef_lisp">my-unsafe-func</span></span><span class="entity entity_paren entity_paren_lisp">)</span>
    <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">println</span> <span class="entity entity_symbol entity_symbol_lisp">my-var</span><span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">)</span></span></pre>
<p>Do this:</p>
<pre class="code"><span class="source source_newlisp"><span class="entity entity_paren entity_paren_lisp">(</span><span class="meta meta_function meta_function_lisp"><span class="storage storage_type storage_type_function-type storage_type_function-type_lisp">define</span> <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_functiondef entity_name_functiondef_lisp">my-safe-func</span></span> <span class="entity entity_symbol entity_symbol_lisp">my-var</span><span class="entity entity_paren entity_paren_lisp">)</span>
    <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">println</span> <span class="entity entity_symbol entity_symbol_lisp">my-var</span><span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">)</span></span></pre>
<p>It&#8217;s a small price to pay for the performance improvement, and oftentimes it&#8217;s actually quite handy to have dynamic scope (especially in combination with the no-longer taboo <span class="code">eval</span>). If you need lexical scope though, newLISP <a href="http://www.newlisp.org/downloads/newlisp_manual.html#expand">has</a> <a href="http://www.newlisp.org/downloads/newlisp_manual.html#letex">you</a> <a href="http://www.newlisp.org/downloads/newlisp_manual.html#contexts">covered</a>.</p>
<h4>Parallel Processing</h4>
<p>newLISP takes an interesting approach for running code in parallel. Whereas Clojure uses <a href="http://clojure.org/refs">advanced methods for multi-threading and ensuring safety</a>, newLISP simply uses its small size and lets the Operating System do all the work!</p>
<p>There are no threads. Writing safe, parallel code is simple through <a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-19">actors</a> and <a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-18">spawn/sync</a> because newLISP <i>simply forks itself</i>. Its modest stature makes this a fairly cheap operation, allowing the OS to handle scheduling and memory-protection. Try forking a JVM&#8230; <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<h4>Excellent Documentation and Community</h4>
<p>newLISP&#8217;s documentation <a href="http://www.newlisp.org/downloads/manual_frame.html">is one of the best examples of excellent documentation that I&#8217;ve ever seen</a>, simply surpassing the documentation for any other LISP that I&#8217;m aware of. You don&#8217;t need to shell out money for a book to learn it, and that&#8217;s because it doesn&#8217;t need a book! The short manual included with the reference documentation is all you&#8217;ll need to learn the language. Its documentation is one of the primary reasons that I was able to successfully procrastinate for my midterm.</p>
<p>If I had to pick a word to describe <a href="http://newlispfanclub.alh.net/forum/index.php">newLISP&#8217;s community</a> it would probably be <b>&#8220;cozy&#8221;</b> (and for Common LISP it would probably be &#8220;abrasive&#8221;). Everyone&#8217;s question is heard and answered in a friendly and rapid manner, and there is no formality. Lutz Mueller will often answer your question or incorporate your suggestions directly into the language. It&#8217;s a small community, yes, but it&#8217;s also agile and capable of rapid change without politics.</p>
<h4>Other Goodies</h4>
<p>There are <b>many other goodies</b> that I won&#8217;t dwell on:</p>
<ul>
<li><a href="http://www.newlisp.org/downloads/newlisp_manual.html#eval_rules">Two kinds of syntax for verbatim strings</a></li>
<li><a href="http://newlispfanclub.alh.net/forum/viewtopic.php?f=16&#038;t=2770&#038;p=15571#p15571">Readline support in REPL with tab completion</a></li>
<li><a href="http://www.newlisp.org/downloads/newlisp_manual.html#unicode_utf8">Full Unicode Support, Strings are UTF8</a></li>
<li><a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-21">Simple and powerful distributed computing</a></li>
<li><a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-22">Built-in web server</a></li>
<li><a href="http://www.newlisp.org/downloads/newlisp_manual.html#indexing">Implicit indexing and slicing for arrays, lists and strings</a></li>
<li><a href="http://www.newlisp.org/downloads/newlisp_manual.html#loading_contexts">Simple archiving and loading of state</a></li>
<li><a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-23">Simple interface to C</a> (means you&#8217;re never at a loss for fast libraries)</li>
</ul>
<h3>Conclusion + Related Links</h3>
<p>newLISP is a true diamond in the rough, sorely under-hyped, but a thing of beauty nevertheless.</p>
<p>If you found this post interesting, you may find some of the links below worth visiting:</p>
<ul>
<li><a href="http://www.newlisp.com">newLISP Homepage</a></li>
<li><a href="http://www.rundragonfly.com">Dragonfly&mdash;A newLISP Web Framework</a></li>
<li><a href="http://kazimirmajorinc.blogspot.com/">Kazimir Majorinc&#8217;s Blog</a></li>
<li><a href="http://unbalanced-parentheses.nfshost.com/">Cormullion&#8217;s Blog</a></li>
<li><a href="http://www.newlisp.org/index.cgi?Code_Contributions">Even larger list of newLISP related links</a></li>
<li>Twitter: <a href="http://twitter.com/newlisp">@newlisp</a>, <a href="http://twitter.com/taoeffect">@taoeffect</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2010/01/how-newlisp-took-my-breath-and-syntax-away/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Introducing Objective newLISP</title>
		<link>http://www.taoeffect.com/blog/2009/12/introducing-objective-newlisp/</link>
		<comments>http://www.taoeffect.com/blog/2009/12/introducing-objective-newlisp/#comments</comments>
		<pubDate>Tue, 08 Dec 2009 08:09:17 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Free Stuff]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[newLISP]]></category>
		<category><![CDATA[greg]]></category>
		<category><![CDATA[ObjNL]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=1318</guid>
		<description><![CDATA[newLISP is an awesome language that I use for all of my scripting needs, but one thing that is missing from it is a nice way of doing real object oriented programming. By default it supports a pseudo-OOP paradigm called FOOP, but FOOP is simply inadequate for doing some of the most rudimentary of OOP [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.newlisp.org">newLISP</a> is an awesome language that I use for all of my scripting needs, but one thing that is missing from it is a nice way of doing real object oriented programming.</p>
<p>By default it supports a pseudo-OOP paradigm called <a href="http://www.newlisp.org/downloads/newlisp_manual.html#foop">FOOP</a>, but FOOP is simply inadequate for doing some of the most rudimentary of OOP tasks, such as allowing objects to hold references to each other.</p>
<p>That is why I&#8217;m announcing <b>Objective newLISP: Real Object Oriented Programming for newLISP</b>.</p>
<h3>Let&#8217;s Dive In</h3>
<p>Objective newLISP&mdash;ObjNL for short&mdash;is modeled after parts of Objective-C and Java. Let&#8217;s open up a REPL and begin:</p>
<pre class="code terminal">$ newlisp ObjNL.lsp
newLISP v.10.1.6 on OSX IPv4 UTF-8, execute 'newlisp -h' for more info.
<b></b>
&gt; </pre>
<h4>Classes</h4>
<p>Classes are simply contexts and are defined using the function <span class="code">new-class</span>:</p>
<pre class="code terminal">&gt; (new-class 'Foo)
Foo</pre>
<p>If we wanted to create a subclass of <span class="code">Foo</span> called <span class="code">Bar</span> we can easily do so:</p>
<pre class="code terminal">&gt; (new-class 'Bar Foo)
Bar</pre>
<p>We can see that <span class="code">Foo</span> is the superclass of <span class="code">Bar</span>:</p>
<pre class="code terminal">&gt; Bar:@super
Foo</pre>
<p>And that all classes inherit from <span class="code">ObjNL</span>:</p>
<pre class="code terminal">&gt; Foo:@super
ObjNL</pre>
<h4>Objects</h4>
<p>Objects are instantiated from classes using the function <span class="code">instantiate</span>. They are contexts too:</p>
<pre class="code terminal">&gt; (setf obj (instantiate Foo))
Foo#1</pre>
<p>As we&#8217;re subverting newLISP&#8217;s <a href="http://www.newlisp.org/MemoryManagement.html">ORO memory management model</a> to gain real OOP, we should deallocate it manually when we&#8217;re through using it. I will cover the topic of <b>memory management</b> last.</p>
<h4>Constructors</h4>
<p>Constructors are defined using the <a href="http://www.newlisp.org/downloads/newlisp_manual.html#default_function">default function</a>. Let&#8217;s define constructors for <span class="code">Foo</span> and <span class="code">Bar</span> (suppose we entered this into the REPL between a pair of <span class="code">[cmd][/cmd]</span> tags):</p>
<pre class="code"><span class="source source_newlisp"><span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">context</span> <span class="entity entity_symbol entity_symbol_lisp">Foo</span><span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">(</span><span class="meta meta_function meta_function_lisp"><span class="storage storage_type storage_type_function-type storage_type_function-type_lisp">define</span> <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_functiondef entity_name_functiondef_lisp">Foo:Foo</span></span> <span class="entity entity_symbol entity_symbol_lisp">_bar</span><span class="entity entity_paren entity_paren_lisp">)</span>
    <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">setf</span> <span class="entity entity_symbol entity_symbol_lisp">bar</span> <span class="entity entity_symbol entity_symbol_lisp">_bar</span><span class="entity entity_paren entity_paren_lisp">)</span>
    <span class="constant constant_language constant_language_lisp">true</span>
<span class="entity entity_paren entity_paren_lisp">)</span>

<span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">context</span> <span class="entity entity_symbol entity_symbol_lisp">Bar</span><span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">(</span><span class="meta meta_function meta_function_lisp"><span class="storage storage_type storage_type_function-type storage_type_function-type_lisp">define</span> <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_functiondef entity_name_functiondef_lisp">Bar:Bar</span></span> <span class="entity entity_symbol entity_symbol_lisp">_foo</span><span class="entity entity_paren entity_paren_lisp">)</span>
    <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">setf</span> <span class="entity entity_symbol entity_symbol_lisp">foo</span> <span class="entity entity_symbol entity_symbol_lisp">_foo</span><span class="entity entity_paren entity_paren_lisp">)</span>
    <span class="constant constant_language constant_language_lisp">true</span> <span class="comment comment_line comment_line_semicolon comment_line_semicolon_lisp"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_lisp">;</span> don't allow ourselves to be deallocated
</span><span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">context</span> <span class="entity entity_symbol entity_symbol_lisp">MAIN</span><span class="entity entity_paren entity_paren_lisp">)</span></span></pre>
<p>Note the extra <span class="code">true</span> at the end of each constructor. This is important because if the constructor returns <span class="code">nil</span> that tells ObjNL that an error occurred and to therefore deallocate the object immediately. Thus if <span class="code">_bar</span> were <span class="code">nil</span> and we didn&#8217;t have that <span class="code">true</span> the object would be deallocated, and we don&#8217;t want that.</p>
<p>When we call <span class="code">instantiate</span> with extra arguments they are passed to the constructor:</p>
<pre class="code terminal">&gt; (setf obj (instantiate Foo (instantiate Bar)))
Foo#2</pre>
<p>We can see that the instance variables were properly set:</p>
<pre class="code terminal">&gt; obj:bar
Bar#1
> obj:bar:foo

ERR: symbol expected : "obj:bar:foo"</pre>
<p>Huh. We were able to check <span class="code">obj:bar</span> but <span class="code">obj:bar:foo</span> resulted in an error. It seems newLISP treats the entire thing as a symbol if there&#8217;s more than one colon, instead of assuming we&#8217;re doing multiple context lookups.</p>
<p>Thankfully Objective newLISP has you covered.</p>
<h4>Deep Value and Symbol Access</h4>
<pre class="code terminal">&gt; (. obj bar foo)
nil</pre>
<p>The <b>dot macro</b> lets us look up the value of a symbol that we want through several object references. I&#8217;ll refer to this as &#8220;deep value access&#8221;. Sometime we want the <i>symbol</i> instead of the value, for example say for fun we want to create a circular reference between the objects <span class="code">obj</span> and <span class="code">obj:bar</span>. We can do this using the <b>dot-reference macro</b>:</p>
<pre class="code terminal">&gt; (.&#038; obj bar foo)
Bar#1:foo
&gt; (set (.&#038; obj bar foo) obj)
Foo#2</pre>
<p>The dot-reference macro allows for &#8220;deep symbol access&#8221;, it returns the context-qualified symbol for an object&#8217;s instance variable. Now we can show that our circular reference works:</p>
<pre class="code terminal">&gt; (. obj bar foo bar foo)
Foo#2
&gt; (= obj (. obj bar foo bar foo))
true</pre>
<h4>Interfaces</h4>
<p>Most object oriented systems have the concept of an <b>interface</b>, sometimes referred to as a <b>protocol</b>. Interfaces define a set of functions that a class can choose to implement or &#8220;conform&#8221; to. Objective newLISP has them too, and refers to them as interfaces even though they are technically <a href="http://en.wikipedia.org/wiki/Mixin">mixins</a>.</p>
<p>Let&#8217;s define a simple interface called <span class="code">protocol</span>:</p>
<pre class="code terminal">&gt; (define (protocol:test) "hello!")
(lambda () "hello!")</pre>
<p>There are two ways to implement an interface. You can specify a list of them when creating a new class:</p>
<pre class="code terminal">&gt; (new-class 'Foo ObjNL '(protocol))
Foo</pre>
<p>Or you can add them to a class or object after its definition. We actually want to do this right now because we instantiated <span class="code">obj</span> prior to adding <span class="code">protocol</span> to <span class="code">Foo</span>&#8216;s list of interfaces. We can check to see this is true by asking if <span class="code">obj</span> implements <span class="code">protocol</span>:</p>
<pre class="code terminal">&gt; (implements? protocol obj)
nil</pre>
<p>So the second way to add an interface to an object or class is to use the function <span class="code">add-interface</span>:</p>
<pre class="code terminal">&gt; (add-interface protocol obj)
(protocol Foo ObjNL)</pre>
<p>Now <span class="code">obj</span> should implement it, so we can try it out:</p>
<pre class="code terminal">&gt; (if (implements? protocol obj) (obj:test))
"hello!"</pre>
<p>The only real difference between an interface and a class is that a class has a constructor (default function) and ultimately inherits from <span class="code">ObjNL</span>. You can use <span class="code">implements?</span> to check inheritance as well:</p>
<pre class="code terminal">&gt; (implements? ObjNL obj)
true</pre>
<h4>Memory Management</h4>
<p>The last, and perhaps most important topic, is what to do with all those objects you&#8217;ve got lying around, also referred to as &#8220;memory management.&#8221;</p>
<p>Objective newLISP supports two styles of memory management: manual and reference counting.</p>
<p><b>Manual memory management</b> is simple: <span class="code">instantiate</span> your object, and when you&#8217;re done with it, <span class="code">deallocate</span> it!</p>
<pre class="code terminal">&gt; (setf b (instantiate Bar))
Bar#2
&gt; (deallocate b)
true</pre>
<p><b>Reference counting</b> is done the same way it is done in <a href="http://en.wikipedia.org/wiki/Objective-C">Objective-C</a>.  Each object starts with a <b>reference count</b> of <span class="code">1</span>. When you want to hold onto that object you <span class="code">retain</span> it, and when you&#8217;re through with it you <span class="code">release</span> or <span class="code">autorelease</span> it (which decrements the reference count). When the reference count hits zero the object is deallocated by <span class="code">deallocate</span>:</p>
<pre class="code terminal">&gt; (setf b (instantiate Bar))
Bar#3
&gt; (release b)
true</pre>
<p>I will cover <span class="code">autorelease</span> next, but I won&#8217;t go to great lengths to explain how all of this reference counting stuff works. If you&#8217;re unfamiliar with it, just know that it&#8217;s not complicated. If you want some practice make an iPhone app. <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<p>To illustrate <span class="code">autorelease</span>  I will implement the method <span class="code">ObjNL:dealloc</span>, which is called on an object just before it is deallocated.</p>
<pre class="code terminal">&gt; (define (Bar:dealloc) (println Bar:@self " has been deallocated!"))
(lambda () (println "Object " Bar:@self " has been deallocated!"))
&gt; (push-autorelease-pool)
(())
&gt; (dotimes (_ 5) (autorelease (instantiate Bar)))
Bar#8
&gt; (pop-autorelease-pool)
Bar#8 has been deallocated!
Bar#7 has been deallocated!
Bar#6 has been deallocated!
Bar#5 has been deallocated!
Bar#4 has been deallocated!
true</pre>
<p>One important point to mention is that deallocating objects in newLISP versions 10.1.8 or older is <b>very slow</b>. The details of why this is has to do with safety (which I discuss in the box below), but needless to say it was too slow to be acceptable. I contacted Lutz Mueller, the author of newLISP, and he agreed to introduce an &#8220;unsafe&#8221; optimization into the <span class="code">delete</span> function. In versions 10.1.9 and later, deallocating Objective newLISP objects is approximately <b>480 times faster</b>.</p>
<p>Because of this, it&#8217;s strongly recommended to use Objective newLISP with <b>newLISP 10.1.9 or later</b>. Currently the latest development release is 10.1.8, however Lutz graciously made this optimization available online in a development version of 10.1.9. Click <a href="http://www.newlisp.org/downloads/development/latest/newlisp-10.1.9-dev.tgz">here to grab the source</a> for this version. This link will expire soon, when it does you can get the latest development release <a href="http://www.newlisp.org/downloads/development/">here</a>.</p>
<div class="box" style="margin-bottom:20px">
<h4>Cautionary Note!</h4>
<p style="margin-bottom:5px">There are two situations to watch out for when using Objective newLISP:</p>
<p style="margin-bottom:5px"><b>#1: Unbound References in Functions</b></p>
<p style="margin-bottom:5px">Instead of this:</p>
<pre class="code"><span class="source source_newlisp"><span class="entity entity_paren entity_paren_lisp">(</span><span class="meta meta_function meta_function_lisp"><span class="storage storage_type storage_type_function-type storage_type_function-type_lisp">define</span> <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_functiondef entity_name_functiondef_lisp">modify-obj</span></span><span class="entity entity_paren entity_paren_lisp">)</span>
    <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">setf</span> <span class="entity entity_symbol entity_symbol_lisp">obj:bar</span> <span class="constant constant_numeric constant_numeric_lisp">5</span><span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">setf</span> <span class="entity entity_symbol entity_symbol_lisp">obj</span> <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">instantiate</span> <span class="entity entity_symbol entity_symbol_lisp">Foo</span><span class="entity entity_paren entity_paren_lisp">))</span>
<span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">modify-obj</span><span class="entity entity_paren entity_paren_lisp">)</span></span></pre>
<p style="margin-bottom:5px">Do this:</p>
<pre class="code"><span class="source source_newlisp"><span class="entity entity_paren entity_paren_lisp">(</span><span class="meta meta_function meta_function_lisp"><span class="storage storage_type storage_type_function-type storage_type_function-type_lisp">define</span> <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_functiondef entity_name_functiondef_lisp">modify-obj</span></span> <span class="entity entity_symbol entity_symbol_lisp">obj</span><span class="entity entity_paren entity_paren_lisp">)</span>
    <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">setf</span> <span class="entity entity_symbol entity_symbol_lisp">obj:bar</span> <span class="constant constant_numeric constant_numeric_lisp">5</span><span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">)</span>
<span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">setf</span> <span class="entity entity_symbol entity_symbol_lisp">obj</span> <span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">instantiate</span> <span class="entity entity_symbol entity_symbol_lisp">Foo</span><span class="entity entity_paren entity_paren_lisp">))</span>
<span class="entity entity_paren entity_paren_lisp">(</span><span class="entity entity_name entity_name_function entity_name_function_lisp">modify-obj</span> <span class="entity entity_symbol entity_symbol_lisp">obj</span><span class="entity entity_paren entity_paren_lisp">)</span></span></pre>
<p>If you don&#8217;t do that, newLISP will read the <span class="code">obj:bar</span> in the definition of <span class="code">modify-obj</span> and instantly create and protect a context called <span class="code">obj</span>, making it impossible to <span class="code">setf</span> the <span class="code">obj</span> later on.</p>
<p style="margin-bottom:5px"><b>#2: Dangling References</b></p>
<p style="margin-bottom:5px">Use extreme caution when holding reference(s) to an object in a list or some other container! If that reference is later deallocated and you try to access it, bad things will happen:</p>
<pre class="code terminal">&gt; (setf b (instantiate Bar))
Bar#9
&gt; (push b alist)
Bar#9
&gt; (deallocate b)
Bar#9 has been deallocated!
true
&gt; alist
Bus error</pre>
<p style="margin-bottom:5px">Normally this would not be a problem, the object in <span class="code">alist</span> would simply be replaced with <span class="code">nil</span> upon its deallocation. However, since we&#8217;re using the fast, unsafe version of <span class="code">delete</span> to do our deallocation, newLISP will not do that. It is the same situation as when attempting to access free&#8217;d memory in C/C++/Objective-C.</p>
<p style="margin-bottom:5px">Instead we should use <span class="code">retain</span>/<span class="code">release</span>:</p>
<p class="last">
<pre class="code terminal">&gt; (setf b (instantiate Bar))
Bar#9
&gt; (push (retain b) alist)
Bar#9
&gt; (release b)
nil
&gt; alist
(Bar#9)
&gt; (release (pop alist))
Bar#9 has been deallocated!
true
&gt; alist
()</pre>
</p>
</div>
<h4>When to use FOOP</h4>
<p>Objective newLISP is not the answer to all OOP problems in newLISP. <a href="http://www.newlisp.org/downloads/newlisp_manual.html#foop">FOOP</a> has its place too. If you&#8217;re dealing with a situation where you may end up needing lots of objects, FOOP is probably the better choice. Although you can&#8217;t do full-blown OOP with it, FOOP objects can use far less memory than ObjNL objects because in ObjNL, methods are stored in each object, not in the class. After trying out both you should have a good feeling for when to use one over the other (i.e., if the limitations of FOOP start to become obvious).</p>
<h4>Download and API</h4>
<p><a href="http://github.com/taoeffect/objective-newlisp">You can grab Objective newLISP from Github.</a></p>
<p>Access the <a href="/newlisp/ObjNL.lsp.html">Objective newLISP API</a>.</p>
<p>And for news, follow <a href="http://twitter.com/taoeffect">@taoeffect</a> and <a href="http://twitter.com/newlisp">@newlisp</a> on twitter.</p>
<p>Thanks for checking out Objective newLISP!</p>
<p>Enjoy! <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2009/12/introducing-objective-newlisp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building a better lock: TESharedObject</title>
		<link>http://www.taoeffect.com/blog/2009/08/building-a-better-lock-tesharedobject/</link>
		<comments>http://www.taoeffect.com/blog/2009/08/building-a-better-lock-tesharedobject/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 01:36:57 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Free Stuff]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[greg]]></category>
		<category><![CDATA[locks]]></category>
		<category><![CDATA[TESharedObject]]></category>
		<category><![CDATA[threads]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=835</guid>
		<description><![CDATA[While I&#8217;m happy to see Grand Central in Snow Leopard, I won&#8217;t be using it in any of our applications anytime soon because that means we&#8217;d have to turn our backs on all those PPC users out there, and everyone who has yet to upgrade to Snow Leopard. I suspect that this represents a sizable [...]]]></description>
			<content:encoded><![CDATA[<p>While I&#8217;m happy to see Grand Central in Snow Leopard, I won&#8217;t be using it in any of our applications anytime soon because that means we&#8217;d have to turn our backs on all those PPC users out there, and everyone who has yet to upgrade to Snow Leopard. I suspect that this represents a sizable chunk of the OS X using population, at least at the moment.</p>
<p>It would also be nice if we could use <a href="http://clojure.org/">Clojure</a> for writing Cocoa apps, but Apple decided to <a href="http://developers.slashdot.org/article.pl?sid=05/07/11/1833252">drop the ball on that one</a>.</p>
<p>However, that doesn&#8217;t mean we still can&#8217;t write good, fast, multithreaded code.</p>
<h3>Actors and Shared Data</h3>
<p>Right now we&#8217;re in the process of rewriting parts of Espionage&#8217;s helper program, which is fairly multithreaded and does most of Espionage&#8217;s heavy-lifting. Currently we are using <b>mutex locks</b> (in the form of NSLock) to synchronize some of the shared data in the application, and while locks are &#8220;OK&#8221;, they can start to get messy when you&#8217;ve got a lot going on.</p>
<p>That&#8217;s why we&#8217;re going to convert the helper to use actors (courtesy of <a href="http://www.plausiblelabs.com/">Plausible Labs</a>&#8216; great <a href="http://code.google.com/p/plactorkit/">PLActorKit</a>). But even when you&#8217;ve structured your code to use the actor approach, you still have a problem if those actors need to operate on data that&#8217;s shared with other actors or other threads. This is where locks could come in, but locks tend to suck.</p>
<p>Locks are slow, everyone knows that, but in our experience they can also encourage bad code because you can associate a lock with just about anything, it doesn&#8217;t have to be a specific piece of data, it can be a group of actions operating on that data, or data related to it. When you don&#8217;t have consistency, things can get out of hand.</p>
<p>So I&#8217;ve written a class that aims to solve these two problems with locks.</p>
<h3>TESharedObject</h3>
<p>When you hold a lock, you prevent any other thread from accessing the data that it&#8217;s protecting, regardless of whether that is necessary or not. What if the data that you&#8217;re protecting is often only read from? Then despite the fact that it&#8217;s perfectly fine for multiple threads to read from a piece of data simultaneously, each reader has to wait in line for the lock to become available. This can really slow things down.</p>
<p>TESharedObject is a replacement for locks that takes this into account. It changes the &#8220;lock&#8221; paradigm in two ways:</p>
<p>First off, it&#8217;s a <b>wrapper around shared data</b>, that is as opposed to a lock, which is just another &#8220;thing&#8221; that you arbitrarily decide is associated with a piece of data, a decision that you may or may not change your mind about as your code evolves.</p>
<p>The other difference is that unlike a lock, it allows multiple readers to access the data at the same time, provided no one&#8217;s writing to it. Databases often take this same approach to improve performance.</p>
<h3>Semaphores</h3>
<p>TESharedObject implements a basic algorithm using the <b>semaphore</b> primitive. Semaphores aren&#8217;t used very often in Cocoa programming, so if you&#8217;re unfamiliar with them you&#8217;ll be forgiven. Quick overview: a semaphore is an entity that has a count associated with it. You can increase the count by calling, say, &#8220;up&#8221; on it, or decrease it by calling &#8220;down&#8221; on it. If you call &#8220;down&#8221; on it when the count is zero, you block until some other thread increases the count.</p>
<p>So, say we have a database, and we want people to be able to read from it safely simultaneously when no one&#8217;s writing to it. By using two semaphores and keeping track of how many people are reading we can accomplish this like so (pseudo-code):</p>
<pre class="code"><span class="source source_objc">semaphore <span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span> = <span class="constant constant_numeric constant_numeric_c">1</span>;
semaphore <span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span> = <span class="constant constant_numeric constant_numeric_c">1</span>;
<span class="storage storage_type storage_type_c">int</span> readerCount = <span class="constant constant_numeric constant_numeric_c">0</span>;

reader:
    down(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span>);
    <span class="keyword keyword_control keyword_control_c">if</span> (++readerCount==<span class="constant constant_numeric constant_numeric_c">1</span>)
        down(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span>);
    up(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span>);
    access_database();
    down(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span>);
    <span class="keyword keyword_control keyword_control_c">if</span> (--readerCount == <span class="constant constant_numeric constant_numeric_c">0</span>)
        up(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span>);
    up(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span>);

writer:
    down(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span>);
    access_database();
    up(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span>);</span></pre>
<p>Here the semaphore <span class="code">sAccess</span> is used as the &#8220;lock&#8221; on the database, or more accurately, to suspend the next thread that calls &#8220;down&#8221; on it. Only the <i style="color:inherit">first</i> reader will call down on <span class="code">sAccess</span>. A second semaphore <span class="code">sRead</span> is used as a backup to <span class="code">sAccess</span> in the situation that another reader is already suspended on <span class="code">sAccess</span>.</p>
<p>The code for the writer is simple, all writers decrement <span class="code">sAccess</span>&#8216;s count, meaning a single writer is enough to stop everyone.</p>
<h3>Building A Better Lock</h3>
<p>Now that we have the pseudo-code, we need a design for our lock, and to get the design we need to have some sort of an idea of how we plan on using this lock in practice. I know! It should look something like this:</p>
<pre class="code"><span class="source source_objc"><span class="support support_class support_class_cocoa">NSMutableString</span> *sharedData = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="support support_class support_class_cocoa">NSMutableString</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">stringWithString<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>Poop<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
TESharedObject *superLock = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>TESharedObject <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">alloc</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">initWithObject<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>sharedData</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;

reader:
    <span class="support support_class support_class_cocoa">NSObject</span> *obj = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>superLock <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">borrowForReading</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> like "lock"
</span>    <span class="support support_function support_function_cocoa">NSLog</span>(<span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>We've got an object! Take a look: %@<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>, obj);
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>superLock <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">returnObject</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> like "unlock"
</span>
writer:
    <span class="support support_class support_class_cocoa">NSMutableString</span> *aStr = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>superLock <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">borrowForWriting</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>aStr <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">setString<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>Harro!<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>superLock <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">returnObject</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;</span></pre>
<p>There, that looks pretty good. Our <span class="code">superLock</span> is bound to the data it&#8217;s protecting. When we want to have a look at the data we call <span class="code">-borrowForReading</span> to &#8220;borrow&#8221; it, and once we&#8217;re finished with it we &#8220;return&#8221; the data by calling <span class="code">-returnObject</span>. Simple enough, and it works just like using a lock. All we have to do is make sure that we don&#8217;t write to the data. If we want to write to it, we call <span class="code">-borrowForWriting</span> instead.</p>
<p>Let&#8217;s have a look at what&#8217;s inside.</p>
<p><b>-borrowForReading</b></p>
<pre class="code"><span class="source source_objc">- (<span class="storage storage_type storage_type_objc">id</span>)borrowForReading
{
    semaphore_wait(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span>);
    <span class="keyword keyword_control keyword_control_c">if</span> ( ++readerCount == <span class="constant constant_numeric constant_numeric_c">1</span> )
        semaphore_wait(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span>);
    semaphore_signal(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span>);
    <span class="keyword keyword_control keyword_control_c">return</span> obj;
}</span></pre>
<p>There&#8217;s our pseudo-code! Well, about half of it, I bet you can guess where the other half is. But before we get to that, let&#8217;s take a look at <span class="code">-borrowForWriting</span>:</p>
<p><b>-borrowForWriting</b></p>
<pre class="code"><span class="source source_objc">- (<span class="storage storage_type storage_type_objc">id</span>)borrowForWriting
{
    semaphore_wait(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span>);
    writing = <span class="constant constant_language constant_language_objc">YES</span>;
    <span class="keyword keyword_control keyword_control_c">return</span> obj;
}</span></pre>
<p>Here the code diverges a bit with the introduction of a new variable <span class="code">writing</span>.  We use it so that whether we called <span class="code">-borrowForReading</span> or <span class="code">-borrowForWriting</span>, we only have to call:</p>
<p><b>-returnObject</b></p>
<pre class="code"><span class="source source_objc"><span class="meta meta_implementation meta_implementation_objc"><span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">returnObject</span></span>
</span>{
    <span class="keyword keyword_control keyword_control_c">if</span> ( writing )
    {
        writing = <span class="constant constant_language constant_language_objc">NO</span>;
        semaphore_signal(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span>);
    }
    <span class="keyword keyword_control keyword_control_c">else</span>
    {
        semaphore_wait(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span>);
        <span class="keyword keyword_control keyword_control_c">if</span> ( --readerCount == <span class="constant constant_numeric constant_numeric_c">0</span> )
            semaphore_signal(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sAccess</span>);
        semaphore_signal(<span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sRead</span>);
    }
}</span></span></span></pre>
<p>And that&#8217;s it. We&#8217;re almost done now, if you&#8217;ve made it here, thanks for sticking with me. I only have two more things to show you, and I think it&#8217;ll be worth it.</p>
<h3>TESharedMap</h3>
<p>Another aspect of shared data that we&#8217;ve neglected to address is the notion of &#8220;globality&#8221;. Yes, I did just make that word up, but it has <i>important consequences!</i> When you&#8217;re dealing with shared data, you&#8217;re often dealing with global variables, and dammit, now you&#8217;ve gotta find a place to put them!</p>
<p>A lot of people just put them at the top. They make long laundry lists of static declarations at the top of some file, and for each piece of shared data two declarations are required: the data, and the lock for the data. This can get kinda ugly, and ugly code is often harder to read and maintain. Our TESharedObject suffers from this same problem, it&#8217;d be nice if we could just focus on the data and not have to deal with the lock that&#8217;s associated with it.</p>
<p>We can get close to this with <b>TESharedMap</b>. TESharedMap acts as a &#8220;summoner&#8221;, we tell it: &#8220;Give us our object!&#8221; And it does. We don&#8217;t need to worry about keeping track of the associated TESharedObject, TESharedMap handles that for us. Put something into the map and it magically becomes thread-safe, so long as you remember to retrieve it only through the map.</p>
<p>Here&#8217;s its interface:</p>
<pre class="code"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">TESharedMap</span> <span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc">:</span> <span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc">NSObject</span><span class="meta meta_divider meta_divider_objc"> </span><span class="meta meta_scope meta_scope_interface meta_scope_interface_objc">{
    TESharedObject *sharedMap;
}

<span class="meta meta_function meta_function_objc">+ <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span>TESharedMap *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">map</span></span>;</span>

<span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">borrowObjectForKey</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">key</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">forReadingOnly</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_objc">BOOL</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">readonly</span></span>;</span>
<span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">returnObjectForKey</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">key</span></span>;</span>
<span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">setObject</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">obj</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">forKey</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">key</span></span>;</span>
<span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">removeObjectForKey</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">key</span></span>;</span>

</span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span></span></pre>
<h3>Benchmarks</h3>
<p>What are the performance benefits of using TESharedObject and TESharedMap instead of NSLock and the like? For this I&#8217;ve written 3 programs, they each do the same thing, the only difference is that each uses a different synchronization primitive that we&#8217;ve discussed (TESharedObject, TESharedMap, and NSLock).</p>
<p>Here&#8217;s the TESharedMap version:</p>
<pre class="code" style="height:500px; overflow:auto;"><span class="source source_objc"><span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include">#<span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c">import</span> <span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">&lt;</span>Foundation/Foundation.h<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">&gt;</span></span></span>
<span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include">#<span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c">import</span> <span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>TESharedObject.h<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span></span>
<span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include">#<span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c">import</span> <span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Common.h<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span></span>
<span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include">#<span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c">import</span> <span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Config.h<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span></span>

<span class="storage storage_modifier storage_modifier_c">static</span> <span class="storage storage_type storage_type_c">int</span> reader = <span class="constant constant_numeric constant_numeric_c">0</span>;
<span class="storage storage_modifier storage_modifier_c">static</span> <span class="storage storage_type storage_type_c">int</span> writer = <span class="constant constant_numeric constant_numeric_c">0</span>;
<span class="storage storage_modifier storage_modifier_c">static</span> <span class="storage storage_type storage_type_c">int</span> msgIdx = <span class="constant constant_numeric constant_numeric_c">0</span>;
<span class="storage storage_modifier storage_modifier_c">static</span> <span class="storage storage_type storage_type_c">int</span> tCount = NUM_READERS + NUM_WRITERS;

<span class="storage storage_modifier storage_modifier_c">static</span> <span class="support support_class support_class_cocoa">NSString</span> *msgs<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> = {
    <span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>Hello World!<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>, <span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>how are you?<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>, <span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>random message!<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>, <span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>hope we have enough of these...<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>,
    <span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>I'm sure we will<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>, <span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>there so many!<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>, <span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>How many messages does it take<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>, <span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>to screw in a lightbulb?<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>
};

<span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c">define</span> <span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c">newMsgIdx</span> (msgIdx++%(<span class="keyword keyword_operator keyword_operator_sizeof keyword_operator_sizeof_c">sizeof</span>(msgs)/<span class="keyword keyword_operator keyword_operator_sizeof keyword_operator_sizeof_c">sizeof</span>(msgs<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="constant constant_numeric constant_numeric_c">0</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>)))</span>

<span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">Actor</span> <span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc">:</span> <span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc">NSObject</span><span class="meta meta_divider meta_divider_objc">
</span><span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">readerMain</span></span>;</span>
<span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">writerMain</span></span>;</span>
</span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span>

<span class="meta meta_implementation meta_implementation_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>implementation</span> <span class="entity entity_name entity_name_type entity_name_type_objc">Actor</span>
<span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">readerMain</span></span>
</span>{
    <span class="support support_class support_class_cocoa">NSAutoreleasePool</span> *pool = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="support support_class support_class_cocoa">NSAutoreleasePool</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;

    <span class="storage storage_type storage_type_c">int</span> i=READ_TIMES, readerID = ++reader;

    <span class="keyword keyword_control keyword_control_c">while</span> ( --i &gt; <span class="constant constant_numeric constant_numeric_c">0</span> )
    {
        <span class="support support_function support_function_C99 support_function_C99_c">fprintf</span>(stderr, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Reader <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%d</span> getting message...<span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>, readerID);
        <span class="support support_class support_class_cocoa">NSString</span> *message = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>TESharedMap <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">map</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">borrowObjectForKey<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>OBJ_KEY <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">forReadingOnly<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="constant constant_language constant_language_objc">YES</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
        <span class="support support_function support_function_C99 support_function_C99_c">fprintf</span>(stderr, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Reader <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%d</span> got message: <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%s</span><span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>, readerID, <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>message <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">UTF8String</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>);
        usleep(READ_SLEEP);
        <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>TESharedMap <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">map</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">returnObjectForKey<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>OBJ_KEY</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
    }

    <span class="support support_function support_function_C99 support_function_C99_c">fprintf</span>(stderr, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Reader <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%d</span> done!<span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>, readerID);
    <span class="keyword keyword_control keyword_control_c">if</span> ( --tCount == <span class="constant constant_numeric constant_numeric_c">0</span> )
    {
        <span class="support support_function support_function_C99 support_function_C99_c">printf</span>(<span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>good-bye<span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>);
        <span class="support support_function support_function_C99 support_function_C99_c">exit</span>(<span class="constant constant_numeric constant_numeric_c">0</span>);
    }
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>pool <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">release</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
}
<span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">writerMain</span></span>
</span>{
    <span class="support support_class support_class_cocoa">NSAutoreleasePool</span> *pool = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="support support_class support_class_cocoa">NSAutoreleasePool</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;

    <span class="storage storage_type storage_type_c">int</span> i=WRITE_TIMES, writerID = ++writer;

    <span class="keyword keyword_control keyword_control_c">while</span> ( --i &gt; <span class="constant constant_numeric constant_numeric_c">0</span> )
    {
        <span class="support support_function support_function_C99 support_function_C99_c">fprintf</span>(stderr, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Writer <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%d</span> getting message...<span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>, writerID);
        <span class="support support_class support_class_cocoa">NSMutableString</span> *message = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>TESharedMap <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">map</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">borrowObjectForKey<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>OBJ_KEY <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">forReadingOnly<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>WRITE_MEANS_READ</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
        <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>message <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">setString<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>msgs<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>newMsgIdx<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
        <span class="support support_function support_function_C99 support_function_C99_c">fprintf</span>(stderr, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Writer <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%d</span> set message to: <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%s</span><span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>, writerID, <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>message <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">UTF8String</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>);
        usleep(WRITE_SLEEP);
        <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>TESharedMap <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">map</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">returnObjectForKey<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>OBJ_KEY</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
    }

    <span class="support support_function support_function_C99 support_function_C99_c">fprintf</span>(stderr, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Writer <span class="constant constant_other constant_other_placeholder constant_other_placeholder_c">%d</span> done!<span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>, writerID);
    <span class="keyword keyword_control keyword_control_c">if</span> ( --tCount == <span class="constant constant_numeric constant_numeric_c">0</span> )
    {
        <span class="support support_function support_function_C99 support_function_C99_c">printf</span>(<span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>good-bye<span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>);
        <span class="support support_function support_function_C99 support_function_C99_c">exit</span>(<span class="constant constant_numeric constant_numeric_c">0</span>);
    }
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>pool <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">release</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
}
</span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span>

<span class="storage storage_type storage_type_c">int</span><span class="meta meta_function meta_function_c"> <span class="entity entity_name entity_name_function entity_name_function_c">main</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span><span class="storage storage_type storage_type_c">int</span> argc, <span class="storage storage_type storage_type_c">char</span> <span class="storage storage_modifier storage_modifier_c">const</span> *argv<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">)</span></span>
{
    <span class="support support_class support_class_cocoa">NSAutoreleasePool</span> *pool = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="support support_class support_class_cocoa">NSAutoreleasePool</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;

    <span class="support support_class support_class_cocoa">NSMutableString</span> *message = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="support support_class support_class_cocoa">NSMutableString</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">alloc</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">initWithString<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>msgs<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>newMsgIdx<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>TESharedMap <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">map</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">setObject<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>message <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">forKey<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>OBJ_KEY</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;

    <span class="keyword keyword_control keyword_control_c">for</span> (<span class="storage storage_type storage_type_c">int</span> i=<span class="constant constant_numeric constant_numeric_c">0</span>; i&lt;NUM_READERS; ++i)
        <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="support support_class support_class_cocoa">NSThread</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">detachNewThreadSelector<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>selector</span>(readerMain) <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">toTarget<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>Actor <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">withObject<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="constant constant_language constant_language_objc">nil</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
    <span class="keyword keyword_control keyword_control_c">for</span> (<span class="storage storage_type storage_type_c">int</span> i=<span class="constant constant_numeric constant_numeric_c">0</span>; i&lt;NUM_WRITERS; ++i)
        <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="support support_class support_class_cocoa">NSThread</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">detachNewThreadSelector<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>selector</span>(writerMain) <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">toTarget<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>Actor <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">withObject<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="constant constant_language constant_language_objc">nil</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;

    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> wait for threads to terminate...
</span>    <span class="keyword keyword_control keyword_control_c">while</span> (tCount)
        sleep(<span class="constant constant_numeric constant_numeric_c">1</span>);

    <span class="support support_function support_function_C99 support_function_C99_c">printf</span>(<span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>good-bye<span class="constant constant_character constant_character_escape constant_character_escape_c">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>);
    <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>pool <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">release</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>;
    <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_numeric constant_numeric_c">0</span>;
}</span></code></pre>
<p>The program launches a certain number of readers and writers, and they each access an NSMutableString a certain number of times. To simulate computation, each reader and writer sleeps for a certain amount of time upon accessing the string. The number of readers and writers, as well as other parameters, can be adjusted by modifying the &#8220;Config.h&#8221; file:</p>
<pre class="code"><span class="source source_objc"><span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> play with these parameters
</span><span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c">define</span> <span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c">NUM_READERS</span> <span class="constant constant_numeric constant_numeric_c">4</span></span>
<span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c">define</span> <span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c">NUM_WRITERS</span> <span class="constant constant_numeric constant_numeric_c">4</span></span>
<span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c">define</span> <span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c">READ_TIMES</span> <span class="constant constant_numeric constant_numeric_c">4000</span></span>
<span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c">define</span> <span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c">WRITE_TIMES</span> <span class="constant constant_numeric constant_numeric_c">4000</span></span>
<span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c">define</span> <span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c">READ_SLEEP</span> <span class="constant constant_numeric constant_numeric_c">1000</span></span>
<span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c">define</span> <span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c">WRITE_SLEEP</span> <span class="constant constant_numeric constant_numeric_c">1000</span></span></span></pre>
<p>I ran 4 benchmarks using the *NIX &#8216;time&#8217; command comparing the 3 synchronization primitives against each other by adjusting the number of readers and writers and keeping the other parameters constant.</p>
<p><b>Dramatic Results</b></p>
<p><center><img src="http://www.taoeffect.com/blog/wp-content/uploads/2009/08/TESharedObject-results.png" alt="TESharedObject results" title="TESharedObject results" width="411" height="286" class="alignnone size-full wp-image-912" /></center></p>
<p>First we see that the extra layer that TESharedMap adds on top of TESharedObject is pretty much negligible in terms of performance.</p>
<p>The results for <b>0r/4w</b> is the worst-case scenario for TESharedObject (no readers), and as expected it performs pretty much exactly like the typical lock.</p>
<p>The results for <b>4r/0w</b> is the best-case scenario, when there are only readers accessing the data. This is the real payoff, <b>almost no penalty for accessing shared data!</b> You can&#8217;t get this with mutex locks.</p>
<p>The other two results show what happens when you have both readers and writers, in which case TESharedObject quickly overtakes the mutex lock, but what&#8217;s most interesting is that as you add more readers, TESharedObject takes a fairly negligible hit while the lock&#8217;s performance is significantly degraded. Why?</p>
<p>The reason becomes pretty obvious if you actually run these tests yourself. What happens is that the readers dominate the lock. This happens because in this program, the data is besieged by a constant and unrelenting stream of readers and writers who lust after the data until they&#8217;ve had their fill. In this situation, the more readers you add, the less likely it becomes that a writer will be able to get a hold of it, so what happens is that there&#8217;s suddenly a stampede of readers with virtually unfettered access to the data which they quickly gobble up, and then after most or all of the readers have had their fill the writers get their turn.</p>
<p>So while TESharedObject can provide a significant performance boost, if your lock is highly contested by readers they can shut out any writers. In most of the situations that I&#8217;ve seen locks used, this doesn&#8217;t happen. But if you are using a TESharedObject in a maelstrom like this, you&#8217;ll probably want to subclass it and modify the <span class="code">-borrowForReading</span> method so that it sleeps if the <span class="code">readerCount</span> is too high, which will make it a bit slower, but it will still be at least as fast as a lock, and you&#8217;ll have better looking code.</p>
<p>I think that&#8217;s it for now. All the code in this post, including the code for TESharedObject and TESharedMap, is provided under an BSD-style license and can be downloaded by clicking the icon below:</p>
<p><a href="/other/TESharedObject.zip" style="border:none"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2009/08/TESharedObject.png" alt="TESharedObject" title="TESharedObject" width="137" height="65" class="alignnone size-full wp-image-887" /></a></p>
<p>Enjoy! <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>- Greg (twitter: @<a href="http://twitter.com/taoeffect">taoeffect</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2009/08/building-a-better-lock-tesharedobject/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Bazaar Like Git + &#8216;repoalias&#8217; Plugin</title>
		<link>http://www.taoeffect.com/blog/2009/06/using-bazaar-like-git-repoalias-plugin/</link>
		<comments>http://www.taoeffect.com/blog/2009/06/using-bazaar-like-git-repoalias-plugin/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 19:38:09 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[bazaar]]></category>
		<category><![CDATA[dvcs]]></category>
		<category><![CDATA[greg]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=721</guid>
		<description><![CDATA[Continuing my exploration of distributed version control systems, I decided to take a quick look at the Git: Managing Branches A single git repository can maintain multiple branches of development. To create a new branch named &#8220;experimental&#8221;, use: $ git branch experimental If you now run $ git branch you&#8217;ll get a list of all [...]]]></description>
			<content:encoded><![CDATA[<p>Continuing my <a href="/blog/2009/06/installing-bazaar-1-16-on-os-x/">exploration of distributed version control systems</a>, I decided to take a <a href="http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html">quick look at the Git</a>:</p>
<div class="box" style="margin-bottom:20px">
<h4>Managing Branches</h4>
<p>A single git repository can maintain multiple branches of development. To create a new branch named &#8220;experimental&#8221;, use:</p>
<pre class="code" style="overflow: visible;">$ git branch experimental</pre>
<p>If you now run</p>
<pre class="code" style="overflow: visible;">$ git branch</pre>
<p>you&#8217;ll get a list of all existing branches:</p>
<pre class="code last" style="overflow: visible;">  experimental
* master</pre>
</div>
<p>That&#8217;s strange, I thought.  Bazaar does it a bit differently.  In Bazaar, the branches are often stored in a <a href="http://doc.bazaar-vcs.org/bzr.dev/en/user-reference/bzr_man.html#repositories">shared repository</a>, which is just a special folder that contains the <a href="http://doc.bazaar-vcs.org/bzr.dev/en/user-reference/bzr_man.html#branches">branches</a> in it as subdirectories, but unlike Git, the repository is typically a &#8220;normal&#8221; folder that contains branches which are stored as subdirectories in plain sight to the developer.</p>
<p>Here&#8217;s an example from the <a href="http://doc.bazaar-vcs.org/bzr.dev/en/user-guide/index.html#advanced-shared-repository-layouts">Bazaar User Guide</a>:</p>
<pre class="code" style="overflow: visible;">repository/       # Overall repository
 +- trunk/        # The mainline of development
 +- branches/     # A container directory
 |   +- foo/      # Branch for developing feature foo
 |     ...
 +- tags/         # Container directory
     +- release-X # A branch specific to mark a given release version
        ...</pre>
<p>Hmm&#8230; I actually like how Git does it.  Git &#8220;already works&#8221; with the way I have my existing projects setup.  I don&#8217;t want to move my projects to match the directory structure shown above. Is there any way to use Bazaar in a Git-like manner? Well, I suppose you already know the answer to that, as I wouldn&#8217;t have much of a blog post to write if there wasn&#8217;t! <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h4>Setting up a Git-like workflow with Bazaar</h4>
<p>Being completely new to Bazaar, and to DVCS&#8217; in general, I decided to ask the folks over at <a href="irc://irc.freenode.net/#bzr">#bzr</a>. They were very helpful, and fairly quickly &#8216;mzz&#8217; had an answer:</p>
<p>First, we <span class="code">cd</span> into our project, which is already <a href="http://doc.bazaar-vcs.org/bzr.dev/en/user-guide/index.html#starting-a-project">setup as a bazaar branch</a>:</p>
<pre class="code" style="overflow: visible;">cd path/to/myproject</pre>
<p>Next, we run the following command:</p>
<pre class="code" style="overflow: visible;">bzr init-repo --no-trees .bzr-repo</pre>
<p>That creates a hidden shared repository inside the project folder called <span class="code">.bzr-repo</span>.  We add the <span class="code">&#45;-no-trees</span> option to tell Bazaar not to create unnecessary copies of the <a href="http://doc.bazaar-vcs.org/bzr.dev/en/user-reference/bzr_man.html#working-trees">working tree</a>.</p>
<p>Note that this is quite different from how repositories in Bazaar are normally used, usually they&#8217;re the parent directory.</p>
<pre class="code" style="overflow: visible;">bzr ignore .bzr-repo</pre>
<p>We add the repository itself to the <a href="http://doc.bazaar-vcs.org/bzr.dev/en/user-reference/bzr_man.html#ignore">ignore list</a> so that it&#8217;s not tracked.</p>
<p>Next, we commit the changes and create the main branch, called &#8220;trunk&#8221;:</p>
<pre class="code" style="overflow: visible;">bzr commit -m "added .bzr-repo to ignore list"
bzr branch . .bzr-repo/trunk</pre>
<p>At this point we have <i style="color:inherit">two</i> branches, the one in <span class="code">.bzr-repo/trunk</span> and the branch we started with.  This is no good, we want to be deal with only one branch at a time&mdash;the one we&#8217;re currently working with, and we want that branch to be one of the ones in <span class="code">.bzr-repo</span>.</p>
<p>Thus enters the concept of a <b>lightweight checkout</b>. A <a href="http://doc.bazaar-vcs.org/bzr.dev/en/user-reference/bzr_man.html#checkouts">checkout</a> is very similar in concept to its SVN counterpart, you have a folder were you can make changes to files, and when you commit them they are sent off to some central location.  One of the main differences between checkouts in Bazaar and checkouts in SVN is that in Bazaar the revision history is stored locally within the checkout itself.  But in our setup, we don&#8217;t want that since each branch is stored locally anyway. Having two copies of it wouldn&#8217;t offer any advantage and would just take up space. A <i>lightweight</i> checkout lets us have a checkout without a revision history.</p>
<p>We can tell Bazaar to change the current branch into a checkout that points to <span class="code">.bzr-repo/trunk</span> by using the <a href="http://doc.bazaar-vcs.org/bzr.dev/en/user-reference/bzr_man.html#reconfigure">reconfigure</a> command:</p>
<pre class="code" style="overflow: visible;">bzr reconfigure --lightweight-checkout --bind-to .bzr-repo/trunk .</pre>
<p>That&#8217;s it! <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Now we can continue our work as usual.  Let&#8217;s test this out by adding a new file to the project:</p>
<pre class="code" style="overflow: visible;"><b>$ echo "Version 1.0" > CHANGES<br/>$ bzr add CHANGES</b>
adding CHANGES
<b>$ bzr commit -m "added CHANGES"</b>
Committing to: /Users/gslepak/myproject/.bzr-repo/trunk/
added CHANGES
Committed revision 2.</pre>
<p>Everything seems in order.  We can now use Bazaar like Git:</p>
<pre class="code" style="overflow: visible;"><b>$ bzr branch . .bzr-repo/experimental</b>
Branched 2 revision(s).
<b>$ bzr switch .bzr-repo/experimental</b>
Tree is up to date at revision 2.
Switched to branch: /Users/gslepak/myproject/.bzr-repo/experimental/</pre>
<p>Since Bazaar doesn&#8217;t have an equivalent to the args-less <span class="code">git branch</span> to list the available branches, we just use plain-old &#8216;ls&#8217;:</p>
<pre class="code" style="overflow: visible;"><b>$ ls .bzr-repo/</b>
experimental/ trunk/</pre>
<p>At this point you might be wondering if there&#8217;s a way to get around having to type out the path to the repository each time you use <span class="code">bzr branch</span> and <span class="code">bzr switch</span>&#8230;</p>
<h4>Introducing the &#8216;repoalias&#8217; Plugin</h4>
<p>I asked that question on #bzr and mzz snapped into action, within a few minutes he had a working plugin ready that did just that. Needless to say my head was reeling from his Python kung-fu. <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><b>Repoalias</b> allows you to reference the branch&#8217;s repository like so:</p>
<pre class="code" style="overflow: visible;">bzr branch . repo:experimental
bzr switch repo:experimental
... do work ...
bzr switch repo:trunk
bzr merge repo:experimental
... etc ...</pre>
<p>Getting the plugin is simple:</p>
<pre class="code" style="overflow: visible;">mkdir -p ~/.bazaar/plugins    # create the plugins folder if it doesn't exist
cd ~/.bazaar/plugins
bzr branch lp:~marienz/+junk/repoalias</pre>
<p>That&#8217;s it! Many thanks to mzz and the folks at #bzr for helping me understand this stuff!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2009/06/using-bazaar-like-git-repoalias-plugin/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Installing Bazaar 1.16 on OS X [Updated]</title>
		<link>http://www.taoeffect.com/blog/2009/06/installing-bazaar-1-16-on-os-x/</link>
		<comments>http://www.taoeffect.com/blog/2009/06/installing-bazaar-1-16-on-os-x/#comments</comments>
		<pubDate>Tue, 23 Jun 2009 03:24:24 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[bazaar]]></category>
		<category><![CDATA[dvcs]]></category>
		<category><![CDATA[greg]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=646</guid>
		<description><![CDATA[Recently I decided to bite the bullet and move away from Xcode&#8217;s Snapshots to using a DVCS. After checking out Git, Mercurial, and Bazaar I finally settled on the latter, for now at least. Bazaar is a great, it has excellent documentation on a very well designed website, it&#8217;s incredibly easy to use (one of [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I decided to bite the bullet and move away from Xcode&#8217;s Snapshots to using a <a href="http://en.wikipedia.org/wiki/Distributed_revision_control">DVCS</a>.  After checking out <a href="http://git-scm.com/">Git</a>, <a href="http://www.selenic.com/mercurial/wiki/">Mercurial</a>, and <a href="http://bazaar-vcs.org/">Bazaar</a> I finally settled on the latter, for now at least.</p>
<p><a href="http://bazaar-vcs.org">Bazaar</a> is a great, it has <a href="http://bazaar-vcs.org/Documentation">excellent documentation</a> on a very well designed website, it&#8217;s incredibly easy to use (one of its design goals) so you can focus on what&#8217;s important (coding), it has support for <b>both</b> <a href="http://doc.bazaar-vcs.org/latest/en/user-guide/index.html#distributed-development">distributed</a> and <a href="http://doc.bazaar-vcs.org/latest/en/user-guide/index.html#centralized-development">centralized</a> workflows, it supports <a href="http://doc.bazaar-vcs.org/latest/en/mini-tutorial/index.html#publishing-your-branch-with-sftp">pushing and pulling from SFTP servers</a> that do not have bazaar installations, and it uses revision <i>numbers</i> (instead of hashes), and it does so in a <a href="http://doc.bazaar-vcs.org/latest/en/user-guide/index.html#bazaar-zen">very intelligent way</a>.</p>
<p>Unfortunately the latest version doesn&#8217;t seem to come in a tidy OS X Installer package, nor is it available via <a href="http://www.macports.org/">MacPorts</a> (yet), so here are some tips to install it from source.</p>
<p>If you&#8217;ve previously installed Bazaar using the package installer you&#8217;ll probably want to clear out some of the files it installed prior to installing the new version:</p>
<pre class="code" style="overflow: visible;">cd /Library/Python/2.5/site-packages
sudo rm -rf bzr*
sudo rm -rf Loom-1.4.0dev0-py2.5.egg-info
sudo rm -rf subvertpy*
sudo rm -rf Extmerge-r10-py2.5.egg-info
sudo rm -rf qbzr-0.9.9-py2.5.egg-info
# we'll install the latest versions of these in a bit
sudo rm -rf BzrTools-1.14.0-py2.5.egg-info
sudo rm -rf pycrypto-2.0.1-py2.5.egg-info
sudo rm -rf paramiko*</pre>
<p>We do that to avoid conflicts and because we want to install these plugins ourselves, so that we can use the latest versions.</p>
<h4>Installing Dependencies</h4>
<p>As mentioned in the note above, and on the <a href="http://bazaar-vcs.org/InstallationFaq">InstallationFaq</a>, there are 3 things that come with the package installer that you should install: <a href="http://pypi.python.org/pypi/paramiko/">Paramiko</a> and <a href="http://pypi.python.org/pypi/pycrypto/">pyCrypto</a> (for SFTP support), and <a href="http://bazaar-vcs.org/BzrTools">BzrTools</a>.</p>
<p>Because of the way we&#8217;re installing Bazaar, you should install BzrTools *after* installing Bazaar 1.16 (detailed below).  Installing Paramiko and pyCrypto is simple though, as you only need to download Paramiko (its installer will grab pyCrypto for you):</p>
<ol style="margin-bottom:20px">
<li>Grab the latest version of Paramiko, as of this writing it&#8217;s 1.7.2:
<div style="margin:10px 0px 10px 0px;"><a href="http://www.lag.net/paramiko/download/paramiko-1.7.2.zip">http://www.lag.net/paramiko/download/paramiko-1.7.2.zip</a></div>
</li>
<li>Extract the contents of the archive and &#8216;cd&#8217; into the directory</li>
<li>To build and install run these commands:
<pre class="code" style="margin-top:10px; padding:0px 0px 5px 0px; background-color:inherit; overflow: visible;">python setup.py build
sudo python setup.py install</pre>
</li>
</ol>
<p>Optionally, the InstallationFaq suggests installing <a href="http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/">Pyrex</a> to speed things up.</p>
<h4>Installing Bazaar 1.16</h4>
<p>Download the <a href="http://bazaar-vcs.org/Download">source</a> for 1.16 (<a href="http://edge.launchpad.net/bzr/1.16/1.16/+download/bzr-1.16.tar.gz">direct link</a>). After you&#8217;ve extracted it run these commands from the source dir:</p>
<pre class="code" style="overflow: visible;">python setup.py build
sudo python setup.py install --home /usr/local
sudo mv /usr/local/lib/python/bzr* /Library/Python/2.5/site-packages/</pre>
<p><i style="color:inherit">Note: On Snow Leopard the default Python install is 2.6, not 2.5.</i></p>
<h4>Installing Bazaar Plugins on OS X</h4>
<p>This too isn&#8217;t very clear from the <a href="http://bazaar-vcs.org/BzrPlugins">Bazaar Plugins</a> page. To install a plugin follow these steps:</p>
<ol style="margin-bottom:20px">
<li>Pick a plugin from the plugins page and grab its branch URL, for example the URL for <a href="http://bazaar-vcs.org/Rebase">Rebase</a> is:
<div style="margin:10px 0px 10px 0px;"><a href="http://people.samba.org/bzr/jelmer/bzr-rebase/trunk">http://people.samba.org/bzr/jelmer/bzr-rebase/trunk</a></div>
</li>
<li>In some directory run:
<pre class="code" style="margin-top:5px; padding:0px; background-color:inherit;">bzr branch <i>[branch-URL]</i></pre>
</li>
<li>That will download the plugin source. &#8216;cd&#8217; into the directory, in the above example it&#8217;s &#8220;trunk&#8221;.</li>
<li>Build and install the plugin using the same commands as you used to install the dependencies.</li>
</ol>
<p>That should do it.  One note is that a lot of the plugins are hosted on <a href="https://launchpad.net/">launchpad</a>, in which case grabbing them is simple (using  &#8216;bzr-search&#8217; as an example):
<pre class="code" style="margin-top:20px; margin-left:20px; padding:0px 0px 5px 0px; background-color:inherit; overflow: visible;">bzr branch lp:bzr-search</pre>
<p>Now you can enjoy <a href="http://doc.bazaar-vcs.org/bzr.1.16/en/release-notes/NEWS.html#bzr-1-16-it-s-yesterday-in-california-2009-06-18">the benefits</a> of running the latest version. <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2009/06/installing-bazaar-1-16-on-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ebswitch: EventBox Profile Switcher</title>
		<link>http://www.taoeffect.com/blog/2009/05/ebswitch-eventbox-profile-switcher/</link>
		<comments>http://www.taoeffect.com/blog/2009/05/ebswitch-eventbox-profile-switcher/#comments</comments>
		<pubDate>Tue, 26 May 2009 22:30:55 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Free Stuff]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ebswitch]]></category>
		<category><![CDATA[eventbox]]></category>
		<category><![CDATA[greg]]></category>
		<category><![CDATA[newLISP]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=542</guid>
		<description><![CDATA[My favorite Twitter client is EventBox by The Cosmic Machine. And while it has a million great features like support for Instapaper and a great interface, it&#8217;s missing one critical piece of functionality and that is support for multiple profiles. However, it&#8217;s still possible to use EventBox with multiple profiles, but perhaps not at the [...]]]></description>
			<content:encoded><![CDATA[<p>My favorite Twitter client is <b>EventBox</b> by <a href="http://thecosmicmachine.com/">The Cosmic Machine</a>. And while it has a million great features like support for <a href="http://www.instapaper.com/">Instapaper</a> and a great interface, it&#8217;s missing one critical piece of functionality and that is support for multiple profiles. However, it&#8217;s still possible to use EventBox with multiple profiles, but perhaps not at the same time. </p>
<p>One solution is a great little program called <a href="http://roobasoft.com/rooSwitch/">rooSwitch</a>. It can be used with EventBox to give you the ability to switch between different isolated profiles, each with its own settings. You could configure rooSwitch with multiple EventBox profiles, say for example one for each Twitter account that you use:<br />
<center><img src="http://www.taoeffect.com/blog/wp-content/uploads/2009/05/rooswitch.png" alt="rooSwitch with two twitter profiles" title="rooSwitch with two twitter profiles" width="387" height="366"/></center></p>
<p>While rooSwitch is great, I don&#8217;t have much use for it besides switching EventBox profiles, and I&#8217;m a terminal fiend anyway, so I wrote a simple <a href="http://www.newlisp.org">newLISP</a> script called <b>ebswitch</b> that does this for me.  Here&#8217;s an example session:</p>
<pre class="code"><b>$ ebswitch</b>
ebswitch version 0.2
Usage: /usr/local/bin/ebswitch twitter_profile_name
<b>$ ebswitch espionageapp</b>
taoeffect => espionageapp
Creating fresh account for: espionageapp
Successfully switched to profile: espionageapp
    <i>... EventBox opens, enter 'espionageapp' login information ...</i>
<b>$ ebswitch taoeffect</b>
Quit EventBox? [y|n]: y
espionageapp => taoeffect
Successfully switched to profile: taoeffect</pre>
<h4>Installing ebswitch</h4>
<p>ebswitch is a <a href="http://www.newlisp.org">newLISP</a> script, so to use it you&#8217;ll need to make sure that newLISP is installed (<a href="http://www.newlisp.org/downloads/newlisp-10.0.2-intel.dmg">Intel</a>/<a href="http://www.newlisp.org/downloads/newlisp-10.0.2-ppc.dmg">PPC</a>), and don&#8217;t worry, one of the great things about newLISP is how small it is. Then, after <a href="/other/ebswitch.lsp.zip">downloading</a> ebswitch to your Desktop, install it into your /usr/local/bin (or /usr/bin) like so:</p>
<pre class="code">$ cd ~/Desktop
$ sudo install ebswitch.lsp /usr/local/bin/ebswitch
Password: <i>enter admin password</i></pre>
<p>Enjoy! <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><b>Update:</b> ebswitch 0.2 adds more intelligence and can now quit EventBox for you.</p>
<p><a href="/other/ebswitch.lsp.zip" style="border:none"><img src="http://www.taoeffect.com/blog/wp-content/uploads/2009/05/eb_switch.png" alt="eb_switch.lsp" title="eb_switch.lsp"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2009/05/ebswitch-eventbox-profile-switcher/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programmers: Win a license to Espionage!</title>
		<link>http://www.taoeffect.com/blog/2009/04/programmers-win-a-license-to-espionage/</link>
		<comments>http://www.taoeffect.com/blog/2009/04/programmers-win-a-license-to-espionage/#comments</comments>
		<pubDate>Sat, 04 Apr 2009 23:38:36 +0000</pubDate>
		<dc:creator>Greg Slepak</dc:creator>
				<category><![CDATA[Free Stuff]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[contest]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[newLISP]]></category>

		<guid isPermaLink="false">http://www.taoeffect.com/blog/?p=414</guid>
		<description><![CDATA[I&#8217;m part of the newLISP Fan Club. I consider myself a fan. Over on the boards there is a challenge, and whoever solves it first wins a license to Espionage, just because that&#8217;s something that I can offer to the winner. Contest ends when someone posts the solution on that forum, or on the 11th [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m part of the <a href="http://www.newlisp.org/">newLISP</a> <a href="http://newlispfanclub.alh.net/forum/index.php">Fan Club</a>.  I consider myself a fan. <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Over on the boards <a href="http://newlispfanclub.alh.net/forum/viewtopic.php?f=15&#038;t=2712">there is a challenge</a>, and whoever solves it first wins a license to Espionage, just because that&#8217;s something that I can offer to the winner. <img src='http://www.taoeffect.com/blog/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> </p>
<p>Contest ends when someone posts the solution on that forum, or on the 11th of April.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.taoeffect.com/blog/2009/04/programmers-win-a-license-to-espionage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
