<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-29454526</id><updated>2011-11-27T18:27:42.999-05:00</updated><category term='ruby'/><category term='silly'/><category term='sapir-whorf'/><category term='open source software'/><category term='lsp'/><category term='debugging'/><category term='erlang'/><category term='compilers'/><category term='latex'/><category term='continuations'/><category term='syntax'/><category term='upgrading'/><category term='structure and interpretation of computer programs'/><category term='coroutines'/><category term='presentation'/><category term='prolog'/><category term='software development'/><category term='showers'/><category term='inheritance'/><category term='python'/><category term='analysis'/><category term='switch statement'/><category term='tips'/><category term='animation'/><category term='user interface'/><category term='rails'/><category term='haskell'/><category term='code smells'/><category term='nosql'/><category term='performance'/><category term='programming languages'/><category term='programming challenge'/><category term='comments'/><category term='rant'/><category term='humor'/><category term='recommendation'/><category term='dependency injection'/><category term='parallel programming'/><category term='ood'/><category term='personal'/><category term='java'/><category term='refactoring'/><category term='document-databases'/><category term='quadtree matrices'/><category term='howto'/><category term='awesome'/><category term='programming'/><category term='tutorial'/><category term='aop'/><category term='iterative programming'/><category term='implementation'/><category term='cucumber'/><category term='oop'/><category term='rvm'/><category term='mongodb'/><category term='concurrency'/><category term='null'/><category term='databases'/><category term='rspec'/><category term='copyright'/><category term='cps'/><category term='parrot'/><category term='abstraction'/><category term='functional programming'/><category term='project euler'/><category term='programming style'/><category term='testing'/><category term='LISP'/><category term='system administration'/><title type='text'>Programming During Recess</title><subtitle type='html'>A blog about programming.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default?start-index=101&amp;max-results=100'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>130</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-29454526.post-7868008878886945722</id><published>2010-09-25T16:58:00.001-04:00</published><updated>2010-09-25T16:58:13.200-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='personal'/><title type='text'>Employed Again!</title><content type='html'>&lt;p&gt;The short story: I got a job as a Senior Rails Developer at a company named Centro in downtown Chicago starting October 4.&lt;/p&gt;&lt;h3&gt;The Longer Story&lt;/h3&gt;&lt;p&gt;Two years ago, I decided to leave teaching at the college level.  I had spent six years "teaching" during grad school and ten years at the college level (at liberal arts schools).  I found myself &lt;em&gt;loving&lt;/em&gt; the software development that I did, and I found reasons to develop more software if I could justify it pedagogically (and sometimes even when I couldn't).  Eventually I decided that a career change was in order.&lt;/p&gt;&lt;p&gt;I had fallen in love with &lt;a href="http://en.wikipedia.org/wiki/Agile_software_development"&gt;agile software development&lt;/a&gt;&amp;mdash;&lt;a href="http://en.wikipedia.org/wiki/Extreme_Programming"&gt;Extreme Programming&lt;/a&gt; in particular and &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;Test-Driven Development&lt;/a&gt; especially.  My programming skills were best in Java and Ruby on Rails.  While my Java skills are quite good, I'm not familiar with the common frameworks that Java shops love to use.  So my job search has focused on Ruby on Rails jobs since I've worked on two such projects that have gone into production, and it was easiest to demonstrate my skills.  Plus, I &lt;em&gt;really enjoy&lt;/em&gt; programming in Ruby with the Rails framework.&lt;/p&gt;&lt;p&gt;I few weeks ago I came across a job advert on Github entitled &lt;a href="http://jobs.github.com/positions/4463ed90-a175-11df-9567-22d639a766d0"&gt;"'Rock Stars' and 'Ninjas' Need Not Apply"&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Centro’s technology team is building a web application for streamlining digital media placement. We are seeking talented developers with experience working with Javascript, Coffeescript, SproutCore, JQuery, Ruby, Sinatra, Rails, MongoDB and Postgres. We’re not throwing those in there so we show up in more searches, we actually use all of it in varying amounts.&lt;/p&gt;&lt;p&gt;If you know SmallTalk or Lisp we’d probably also like to talk to you. Folks who send resumes formatted with LaTeX are guaranteed a phone screen.&lt;/p&gt;&lt;p&gt;Centro is a great company to work for — we were listed by Crain’s as one of the best places to work in Chicago. We hire people with zeal for writing excellent code.&lt;/p&gt;&lt;p&gt;If you’ve got something awesome up on GitHub we’d love to have a look.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Those of you who know me and recognize the tech-speak understand why this advert made me &lt;em&gt;very&lt;/em&gt; happy.  &lt;strong&gt;First paragraph:&lt;/strong&gt; they use a lot of cool technologies and actively look to use others; that's my kind of company!  &lt;strong&gt;Second paragraph:&lt;/strong&gt; I got the guaranteed phone screen without trying, and my Scheme experience in grad school counted for LISP experience.  &lt;strong&gt;Third paragraph:&lt;/strong&gt; Cool.  &lt;strong&gt;Fourth paragraph:&lt;/strong&gt; you can &lt;a href="http://github.com/jdfrens/Vitae"&gt;see my resume in LaTeX form on Github&lt;/a&gt;&amp;mdash;and a lot of other projects I've worked on (with varying degrees of awesomeness).&lt;/p&gt;&lt;p&gt;After a phone screen and a day-long on-site interview, they recognized how well I fit what they are looking for; so, starting on October 4, I will be working as a Senior Rails Developer at &lt;a href="http://centro.net/"&gt;Centro&lt;/a&gt; in downtown Chicago.&lt;/p&gt;&lt;p&gt;Centro serves as a middleman between advertisers and websites.  I could try to explain specifically what they do, but if a picture is worth a thousand words, a video is worth a million: check out the &lt;a href="http://www.transis.com/"&gt;demo video for Transis&lt;/a&gt;.  Transis is only a fraction of the software that's being worked on at Centro, but it gives a good idea for what Centro does and (at a meta level) the quality of their work.&lt;/p&gt;&lt;p&gt;I'm really looking forward to my new job and new career.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7868008878886945722?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7868008878886945722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7868008878886945722' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7868008878886945722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7868008878886945722'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/09/employed-again.html' title='Employed Again!'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3917781694260877879</id><published>2010-09-18T12:16:00.001-04:00</published><updated>2010-09-18T12:16:51.322-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='comments'/><category scheme='http://www.blogger.com/atom/ns#' term='humor'/><title type='text'>Funny Code Comments</title><content type='html'>&lt;p&gt;&lt;a href="http://cobaia.net/2010/09/top-funny-source-code-comments/"&gt;"Top funny source code comments"&lt;/a&gt; by Vinícius Krolow at &lt;a href="http://cobaia.net/"&gt;cObaia.net&lt;/a&gt; is worth your time.  There are some straight up jokes (like the comments about recursion) and some about the code (e.g., "They made me write it, against my will.").&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3917781694260877879?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3917781694260877879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3917781694260877879' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3917781694260877879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3917781694260877879'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/09/funny-code-comments.html' title='Funny Code Comments'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-6948362041820641775</id><published>2010-09-10T18:15:00.001-04:00</published><updated>2010-09-10T18:15:37.412-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='awesome'/><title type='text'>I'm Male and 26--35 Years Old, and I Write Happy</title><content type='html'>&lt;p&gt;Apparently, I write like I'm male and 26--35 years old.  A bit off on the age (by five years, let's say).  My writing is also "personal and happy"; if you say so...&lt;/p&gt;&lt;p&gt;I discovered these wonderful facts from &lt;a href="http://urlai.com/"&gt;URL AI&lt;/a&gt; (see &lt;a href="http://urlai.com/url/jdfrens.blogspot.com"&gt;my blog's report from URL AI&lt;/a&gt;).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-6948362041820641775?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/6948362041820641775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=6948362041820641775' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6948362041820641775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6948362041820641775'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/09/i-male-and-26-35-years-old-and-i-write.html' title='I&amp;#39;m Male and 26--35 Years Old, and I Write Happy'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2224366604131305323</id><published>2010-09-04T12:09:00.001-04:00</published><updated>2010-09-04T12:09:38.536-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='system administration'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='rvm'/><title type='text'>Tar Archive Problems Upgrading RVM to 1.0.2</title><content type='html'>&lt;p&gt;When I tried to upgrade RVM yesterday and this morning, I got this result:&lt;/p&gt;&lt;pre&gt;
$ rvm update

rvm 1.0.1 by Wayne E. Seguin (wayneeseguin@gmail.com) [http://rvm.beginrescueend.com/]

info: fetching rvm-1.0.2.tar.gz

info: Extracting rvm-1.0.2.tar.gz ...

error: Error running 'gunzip "/Users/jdfrens/.rvm/archives/rvm-1.0.2.tar.gz" | tar xf - -C /Users/jdfrens/.rvm/src', please check /Users/jdfrens/.rvm/log/extract*.log

info: Installing rvm-1.0.2...

error: Error running 'builtin cd /Users/jdfrens/.rvm/src/rvm-1.0.2/ ; ./install', please check /Users/jdfrens/.rvm/log/install*.log
&lt;/pre&gt;&lt;p&gt;And &lt;code&gt;.rvm/log/extract.error.log&lt;/code&gt; contains entries like this:&lt;/p&gt;&lt;pre&gt;
[2010-09-03 10:06:05] gunzip "/Users/jdfrens/.rvm/archives/rvm-1.0.2.tar.gz" | tar xf - -C /Users/jdfrens/.rvm/src
tar: This does not look like a tar archive
tar: Exiting with failure status due to previous errors
&lt;/pre&gt;&lt;p&gt;Thinking it was &lt;em&gt;maybe&lt;/em&gt; the &lt;code&gt;gnuzip&lt;/code&gt; from &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt; causing the problem, I renamed it to use the system-wide &lt;code&gt;gnuzip&lt;/code&gt; from Apple.  Didn't help.  So I renamed the MacPorts version back to &lt;code&gt;gnuzip&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;RVM had been updated in my system-wide Ruby (from MacPorts); this is how I knew 1.0.2. was out.  So I ran &lt;code&gt;/opt/local/bin/rvm-install&lt;/code&gt; hoping that it would simply update my RVM.  &lt;strong&gt;It worked!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Strangely, it seems to have fixed the update process itself:&lt;/p&gt;&lt;pre&gt;
$ rvm reload      # to load the version from the rvm-install update
$ rvm version

rvm 1.0.2 by Wayne E. Seguin (wayneeseguin@gmail.com) [http://rvm.beginrescueend.com/]

$ rvm update

rvm 1.0.2 by Wayne E. Seguin (wayneeseguin@gmail.com) [http://rvm.beginrescueend.com/]


info: fetching rvm-1.0.2.tar.gz

info: Extracting rvm-1.0.2.tar.gz ...

info: Installing rvm-1.0.2...
$ rvm reload
$ 
&lt;/pre&gt;&lt;p&gt;Just in case this is helpful to someone else out there...&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2224366604131305323?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2224366604131305323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2224366604131305323' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2224366604131305323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2224366604131305323'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/09/tar-archive-problems-upgrading-rvm-to.html' title='Tar Archive Problems Upgrading RVM to 1.0.2'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-905659961936603064</id><published>2010-09-03T20:34:00.001-04:00</published><updated>2010-09-03T20:34:41.279-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><category scheme='http://www.blogger.com/atom/ns#' term='open source software'/><title type='text'>LaTeX Anecdote #2: My Dissertation</title><content type='html'>&lt;p&gt;This is a continuation of my series on LaTeX (&lt;a href="http://jdfrens.blogspot.com/2010/08/typesetting-with-latex.html"&gt;introduction&lt;/a&gt; and &lt;a href="http://jdfrens.blogspot.com/2010/08/latex-anecdote-1-large-multi-author.html"&gt;anecdote #1&lt;/a&gt;).  Much of this particular article is based on a rant I had on my webpages at Calvin.&lt;/p&gt;&lt;h3&gt;One Minute LaTeX&lt;/h3&gt;&lt;p&gt;I used &lt;a href="http://www.gnu.org/software/emacs/"&gt;emacs&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/LaTeX"&gt;LaTeX&lt;/a&gt; to write &lt;a href="http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR568"&gt;my dissertation&lt;/a&gt;.  There's an emacs package called &lt;a href="http://www.gnu.org/software/auctex/"&gt;AUCTeX&lt;/a&gt; that allowed me to hit two keys while editing my LaTeX document, and emacs would process my document.  The package is smart enough to know when to run LaTeX multiple times to generate cross-references as well as when and how to run &lt;a href="http://en.wikipedia.org/wiki/BibTeX"&gt;BibTeX&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;At any time, I could process and view my dissertation &lt;em&gt;within a minute&lt;/em&gt;. Complete with cross references (e.g., "See Figure 5.") and a &lt;em&gt;very&lt;/em&gt; well formatted bibliography.  Formatted as required by Indiana University.&lt;/p&gt;&lt;p&gt;A minute.&lt;/p&gt;&lt;h3&gt;Twelve Hour Word&lt;/h3&gt;&lt;p&gt;Sue, a friend of mine in the Chemistry Department at Indiana University, helped a friend of hers print out her dissertation.  This friend had written the dissertation in Microsoft Word, each chapter in a different file.  It included pictures and graphs written with other commercial software. It took them &lt;em&gt;twelve hours&lt;/em&gt; to get the dissertation to look right.&lt;/p&gt;&lt;p&gt;Twelve hours.&lt;/p&gt;&lt;p&gt;When Sue went to print her dissertation a few months later, she planned for twelve hours, but it took her &lt;em&gt;only eight hours&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Yeah... &lt;em&gt;only&lt;/em&gt; eight hours!  That's insane!  Who would, given a choice, pick a program that demands you fuss around with it for eight hours to get your document to print correctly?&lt;/p&gt;&lt;h3&gt;What about Today?&lt;/h3&gt;&lt;p&gt;Sue and her colleague printed their dissertations with MS Word between 1996 and 1998.  I wonder if they could print their dissertations today with MS Word.  I seriously doubt they would look right.&lt;/p&gt;&lt;p&gt;I finished my dissertation in 2002, and I haven't really tried to regenerate it from the original source files since then.  But it seemed dishonest of me to rant like this without giving it a try.  So I tried.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Fifteen minutes.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Why so long?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;I had to remember the &lt;code&gt;latex&lt;/code&gt; and &lt;code&gt;bibtext&lt;/code&gt; and &lt;code&gt;dvips&lt;/code&gt; commands I needed.  This was because I've been using makefiles lately to process my LaTeX files, but my dissertation was always processed with AUCTeX, not makefiles.  This was actually pretty easy for me to figure out.&lt;/li&gt;&lt;li&gt;I had to convert some figures into EPS (encapsulated PostScript).  I used &lt;a href="http://www.xfig.org/"&gt;xfig&lt;/a&gt; to create figures in my dissertation, and xfig has its own format which LaTeX doesn't recognize.  I wasn't exactly eager to convert the 32 figures by hand, so I spent some time finding some way to automate the process.  I discovered &lt;code&gt;&lt;a href="http://gd.tuwien.ac.at/linuxcommand.org/man_pages/fig2dev1.html"&gt;fig2dev&lt;/a&gt;&lt;/code&gt; which did a great job.&lt;/li&gt;&lt;li&gt;I originally used a tweaked &lt;a href="http://www.bibtex.org/"&gt;BibTeX&lt;/a&gt; format for my bibliography.  (My advisor was &lt;em&gt;very&lt;/em&gt; picky about bibliographies and their formats.)  It appears I don't have that style file anymore, so I switched to a standard format.  But then it also appears I don't have BibTeX set up quite right on my system, but I found a way to get it to work.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I could create a makefile to handle the &lt;code&gt;latex&lt;/code&gt; and &lt;code&gt;bibtex&lt;/code&gt; and other commands and to process the xfig files with &lt;code&gt;fig2dev&lt;/code&gt;.  I could spend another 15 minutes or so to get BibTeX to work the way it should.  And I'd be &lt;em&gt;exactly&lt;/em&gt; where I was when I was working on my dissertation: a minute to generate a perfect PDF of my dissertation.&lt;/p&gt;&lt;h3&gt;Next Time&lt;/h3&gt;&lt;p&gt;I will talk about LaTeX Beamer and creating presentations.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-905659961936603064?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/905659961936603064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=905659961936603064' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/905659961936603064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/905659961936603064'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/09/latex-anecdote-2-my-dissertation.html' title='LaTeX Anecdote #2: My Dissertation'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1879226787447267127</id><published>2010-08-31T20:16:00.001-04:00</published><updated>2010-08-31T20:16:29.718-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><category scheme='http://www.blogger.com/atom/ns#' term='open source software'/><title type='text'>LaTeX Anecdote #1: The Large, Multi-Author Document</title><content type='html'>&lt;p&gt;This is a continuation of &lt;a href="http://jdfrens.blogspot.com/2010/08/typesetting-with-latex.html"&gt;my series on LaTeX&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;I Hate MS Word&lt;/h3&gt;&lt;p&gt;One of the biggest frustrations I ever experienced was putting together a rather large document (over 100 pages) for the Computer Science Department when I was at Calvin College.  The document had to follow a particular format, and we were given a starter Word document.  I &lt;em&gt;really&lt;/em&gt; wanted to turn it into LaTeX, but most of my colleagues were Word users.  Plus, the college administration would prefer Word documents, not PDFs.  It seemed easier to go with Word.&lt;/p&gt;&lt;p&gt;Over the course of a couple of weeks, my colleagues would send me contributions to this document.  Each contribution was formatted a little differently; and as I added those documents to the master document, those formatting changes affected the format of my master document.  Of course, most of the contributions came in the last week and last day before it was due, and so I spent a very late night trying to get the document to look halfway decent and consistent.  It didn't go very well, and I ended up taking my frustration out on my office door by kicking it forcefully a few times.  Fortunately, I didn't break the door, just scuffed it up pretty seriously.  And in the end, the formatting on the document was rather inconsistent, but not grossly so.  It was only ever good enough.&lt;/p&gt;&lt;p&gt;Part of the problem was the amount of time spent on integrating the documents, but my door-kicking problem was the mind-numbing frustration trying to get the document to behave.  Word was usually unhelpful or &lt;em&gt;too&lt;/em&gt; helpful with it's own corrections.&lt;/p&gt;&lt;h3&gt;Should Have Used LaTeX&lt;/h3&gt;&lt;p&gt;Okay, so this post is really a "I frakin' hate MS Word!"  Word failed me, and I didn't try the document in LaTeX.  I thought about converting the document into LaTeX &lt;em&gt;many&lt;/em&gt; time, especially when I took my frustration out on my office door, but I didn't.&lt;/p&gt;&lt;p&gt;What would it have gained me?  First, it would have had a consistent look, and I could have a rather bland consistent look without too much trouble.  Second, to spruce it up (highlight the structure of the document) would have taken very little work: add some LaTeX environments and style them (tweak the font faces and sizes perhaps).&lt;/p&gt;&lt;p&gt;Most of the document was plain text, and converting from Word into text wouldn't have been difficult at all.  As I recall, there were few (if any images), but they're easy to include in a LaTeX document.  There were definitely a few tables, and they might have been harder to convert, but there are compromises that would result in good-looking tables without too much difficulty.&lt;/p&gt;&lt;h3&gt;Next Time&lt;/h3&gt;&lt;p&gt;In my next entry on this topic, I have an anecdote when LaTeX &lt;em&gt;did&lt;/em&gt; win.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1879226787447267127?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1879226787447267127/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1879226787447267127' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1879226787447267127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1879226787447267127'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/latex-anecdote-1-large-multi-author.html' title='LaTeX Anecdote #1: The Large, Multi-Author Document'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2975005961521496251</id><published>2010-08-30T17:44:00.001-04:00</published><updated>2010-08-30T17:44:02.522-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><category scheme='http://www.blogger.com/atom/ns#' term='open source software'/><title type='text'>Typesetting with LaTeX</title><content type='html'>&lt;p&gt;When I taught at Calvin College, I had some web pages where I discussed my love of LaTeX (and my hatred of Microsoft Word).  Since those web pages are no more and since the material would work better on a blog anyway, I'm spreading my love here.&lt;/p&gt;&lt;p&gt;In this blog post, I'm going to talk &lt;em&gt;very&lt;/em&gt; briefly about what LaTeX is.  In future blog posts, I'll give some anecdotes why I love LaTeX so much (and hate MS Word), and I'll talk about using LaTeX Beamer to replace PowerPoint.&lt;/p&gt;&lt;h3&gt;Me and LaTeX&lt;/h3&gt;&lt;p&gt;I started using &lt;a href="http://en.wikipedia.org/wiki/TeX"&gt;TeX&lt;/a&gt; for writing documents (mostly for a topology course) when I was a senior in college (around 1992).  When I started grad school, I moved on to &lt;a href="http://en.wikipedia.org/wiki/LaTeX"&gt;LaTeX&lt;/a&gt; and used it for nearly all of my written assignments.  As a teacher, I used it for writing all my tests and printed assignments for my students.  As a researcher, I wrote several conference papers and my dissertation with LaTeX.  I also used LaTeX for classroom and conference presentations.&lt;/p&gt;&lt;h3&gt;What Is LaTeX?&lt;/h3&gt;&lt;p&gt;These webpages came to my attention recently:&lt;p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://nitens.org/taraborelli/latex/"&gt;"The Beauty of LaTeX"&lt;/a&gt; by Dario Taraborelli.  This is an awesome article about the technical typesetting details that LaTeX does just right.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.osnews.com/story/10766"&gt;"LaTeX isn't for everyone, but it could be for you"&lt;/a&gt; by Andy Roberts.  Roberts provides a good list of reasons to use LaTeX and includes some links to some tutorials.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In short, LaTeX is TeX with more features and defaults.  A LaTeX document is a text document (entered into a &lt;a href="http://en.wikipedia.org/wiki/Text_editor"&gt;text editor&lt;/a&gt;).  The LaTeX text file is processed by the LaTeX executable into a DVI, PostScript, or (these days) PDF file.&lt;/p&gt;&lt;p&gt;I'll date myself with this comparison, but LaTeX (and TeX) is like writing a document with &lt;a href="http://en.wikipedia.org/wiki/WordPerfect#Reveal_codes"&gt;Word Perfect's Reveal Codes&lt;/a&gt; permanently turned on.  A more modern equivalent would be raw HTML.&lt;/p&gt;&lt;p&gt;But better than Reveal Codes or raw HTML, LaTeX is really a programming language, and so you have the power of &lt;strong&gt;abstraction&lt;/strong&gt; to make writing your document easier.&lt;/p&gt;&lt;p&gt;Additionally, LaTeX is based on &lt;strong&gt;logical formatting&lt;/strong&gt; (which &lt;a href="http://jdfrens.blogspot.com/2007/09/physical-versus-logical-formatting.html"&gt;I've blogged about before&lt;/a&gt;).  The idea is that you describe the structure (the logical format) of your document in the document, and then specify the look (the physical format) separately.&lt;/p&gt;&lt;h3&gt;Examples&lt;/h3&gt;&lt;p&gt;Roberts provides this example:&lt;/p&gt;&lt;pre&gt;
% hello.tex - Hello world Latex example
\documentclass{article}

\begin{document}
Hello World!
\end{document}
&lt;/pre&gt;&lt;p&gt;Where does the document begin?  Where does it end?  LaTeX's logical formatting tells exactly how to answer these questions.  Its abstraction mechanism provides the definitions (size of margins, type of font, etc.) for the document environment.&lt;/p&gt;&lt;p&gt;Here's another example (my own):&lt;/p&gt;&lt;pre&gt;
\documentclass{article}

\title{Artists Queued in My iTunes DJ}
\author{Jeremy D. Frens}

\begin{document}
\maketitle
\begin{itemize}
  \item Sufjan Stevens
  \item Glenn Gould
  \item Devo
  \item The Black Keys
\end{itemize}
\end{document}
&lt;/pre&gt;&lt;p&gt;What's the title of the document?  Who wrote it?  If I tell you that &lt;code&gt;itemize&lt;/code&gt; is just LaTeX's name for a bulleted list, what's the content of the document?&lt;/p&gt;&lt;p&gt;There are properties of itemized lists that can be &lt;em&gt;easily&lt;/em&gt; controlled globally.  How would you change &lt;em&gt;all&lt;/em&gt; of the bulleted lists in a Word document?  Find each one, and tweak it.  In LaTeX, you change some settings before you begin the document (where I set the title and author).  If you wanted to change just one list, you can do that, too.  If you want to change some lists but not others, &lt;em&gt;you can create your own abstractions&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;I have a lot of abstractions in my &lt;a href="http://github.com/jdfrens/Vitae/blob/master/Vitae/myvita.tex"&gt;curriculum vitae&lt;/a&gt;.  (You can find my resume in that same repository, but it's rather messy.)  The intent of each section is very clear from the structure of that document, and the logical formatting of that structure comes from the &lt;code&gt;vita&lt;/code&gt; document class that I access at the very beginning of the document.&lt;/p&gt;&lt;h3&gt;Next Time&lt;/h3&gt;&lt;p&gt;Next time I'll describe my experience trying to write a lengthy document with multiple authors with MS Word.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2975005961521496251?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2975005961521496251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2975005961521496251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2975005961521496251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2975005961521496251'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/typesetting-with-latex.html' title='Typesetting with LaTeX'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2781815603400894658</id><published>2010-08-27T20:05:00.002-04:00</published><updated>2010-08-30T14:10:03.329-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Upgrading to Rails 3 and RSpec 2, Part 5: Cucumber</title><content type='html'>&lt;p&gt;My final part of &lt;a href="http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-1.html"&gt;my series on upgrading a Rails app to Rails 3 and RSpec 2&lt;/a&gt; describes some of the issues encountered when upgrading Cucumber.&lt;/p&gt;&lt;p&gt;I upgraded to cucumber 0.8.5 and cucumber-rails 0.3.2.&lt;/p&gt;&lt;h3&gt;Goodbye, Webrat.  Hello, Capybara.&lt;/h3&gt;&lt;/p&gt;On a from-scratch Rails 3 app, I already knew this meant switching from &lt;a href="http://rubygems.org/gems/webrat"&gt;webrat&lt;/a&gt; to &lt;a href="http://rubygems.org/gems/capybara"&gt;capybara&lt;/a&gt;. So in my upgrade, I found it best to run this:&lt;/p&gt;&lt;pre&gt;
ruby script/rails generate cucumber:install --rspec --capybara
&lt;/pre&gt;&lt;p&gt;I replaced what should be safe to replace (e.g., &lt;code&gt;features/step_definitions/web_steps.rb&lt;/code&gt;) and did a hand merge on others (e.g., &lt;code&gt;paths.rb&lt;/code&gt; and &lt;code&gt;env.rb&lt;/code&gt; in &lt;code&gt;features/support&lt;/code&gt;).  This wasn't difficult.&lt;/p&gt;&lt;p&gt;I'm still getting used to capybara, and my sample app probably isn't the best place to learn about it (at least not yet).  I got hooked on selecting with XPaths, and later I discovered the ways to use CSS selectors which would have made the webrat-to-capybara translation much easier.&lt;/p&gt;&lt;h3&gt;Rename Method&lt;/h3&gt;&lt;p&gt;In the step definitions, the most significant change is a name change: &lt;code&gt;page&lt;/code&gt; instead of &lt;code&gt;response&lt;/code&gt;.  Of course, cucumber is happy to complain about this for you, although a project-wide search-and-replace might speed up the refactoring.  (You may actually want to restrict the search to just the &lt;code&gt;features&lt;/code&gt; folder.)&lt;/p&gt;&lt;p&gt;I like the change.  "Page" reflects a bit better what's being testing in a Cucumber scenario.&lt;/p&gt;&lt;h3&gt;Date and Time Selection&lt;/h3&gt;&lt;p&gt;One other painful change involves selecting dates and times.&lt;/p&gt;&lt;p&gt;Rails has helper methods for forms: &lt;code&gt;form.datetime_select&lt;/code&gt; and &lt;code&gt;form.date_select&lt;/code&gt;.  This generates several select inputs (with the &lt;code&gt;select&lt;/code&gt; HTML element) for the various components of the date and/or time.  For example, &lt;code&gt;form.date_select&lt;/code&gt; generates three select inputs for the year, month, and day.  They get goofy (but easily parsed) names like &lt;code&gt;event[start_1i]&lt;/code&gt; for the year component of a &lt;code&gt;start&lt;/code&gt; attribute of an &lt;code&gt;event&lt;/code&gt; object.&lt;/p&gt;&lt;p&gt;Old versions of Cucumber and webrat provided a &lt;code&gt;web_steps.rb&lt;/code&gt; with a step that allowed me to select dates and times generated with these form helpers.  The new Cucumber and capybara do not.&lt;/p&gt;&lt;p&gt;After some advice discovered through a Google search, I ended up with &lt;a href="http://github.com/jdfrens/calvincs/blob/6c9e9cb9bd80cf001ffe150d1d8bedfc7adeab23/features/step_definitions/date_selection_steps.rb"&gt;a satisfactory steps for selecting my date and datetime&lt;/a&gt;.  The result of my Google search is referenced at the top of that file, and it provides a much more general solution (although it didn't quite work for me).  I tailored the code to my domain, but generalizing it wouldn't be too difficult.&lt;/p&gt;&lt;p&gt;It works okay, but I suspect that I'll be changing the way I enter dates and times.  HTML 5 has &lt;a href="http://diveintohtml5.org/forms.html#type-date"&gt;data and time input fields&lt;/a&gt;.  While only Opera 9.0 support these input types, other browsers default to a textfield.  For those other browsers for the time being, I can use a JavaScript data/time selector for the fancy input.  Either way, for testing purposes it would suffice to send a string for the input field.  (See &lt;a href=""&gt;the relevant section of the HTML 5 specification&lt;/a&gt; if you don't believe me.)&lt;/p&gt;&lt;h3&gt;Next Time&lt;/h3&gt;&lt;p&gt;Well, I don't have a next time planned.  Of course, I'm still working on my app, and perhaps something Rails 2-to-3 might come up, but until then, this is it for my series.  I have a couple other blog articles queued up for me to blog on, so I'll be turning my attention there next week.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2781815603400894658?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2781815603400894658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2781815603400894658' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2781815603400894658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2781815603400894658'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-5.html' title='Upgrading to Rails 3 and RSpec 2, Part 5: Cucumber'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1530259284605417747</id><published>2010-08-20T15:08:00.001-04:00</published><updated>2010-08-20T15:08:30.076-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='upgrading'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Upgrading to Rails 3 and RSpec 2, Part 4b: Recursive Rendering</title><content type='html'>&lt;p&gt;Today's "upgrading to RSpec 2 for Rails 3" episode is a direct continuation from &lt;a href="http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part.html"&gt;the previous episode on upgrading the view specs&lt;/a&gt;.  That post got quite long, and this part seemed the best to pull out into its own post.&lt;/p&gt;&lt;p&gt;The topic of discussion is calling &lt;code&gt;render&lt;/code&gt; recursively.&lt;/p&gt;&lt;h3&gt;Recursive Renders&lt;/h3&gt;&lt;p&gt;"Extract partial" is essentially the view's version of &lt;a href="http://www.refactoring.com/catalog/extractMethod.html"&gt;"Extract method"&lt;/a&gt; in a model or controller.  I pull out part of the view into a partial view so that the views are simpler, easier to reason about, and easier to test.&lt;/p&gt;&lt;p&gt;For example, &lt;a href="http://github.com/jdfrens/calvincs/tree/rails3"&gt;the app that I upgraded&lt;/a&gt; displays &lt;a href="http://github.com/jdfrens/calvincs/blob/rails3/app/views/personnel/show.html.erb"&gt;the details of a professor&lt;/a&gt;.  There's a lot of variation that goes into this: how many schools did they go to? do they have research interests listed in the database? do they have an office phone (that they want listed)? do they have a special status (e.g., "department chair")? etc.  I don't want to test these variations all in one &lt;a href="http://github.com/jdfrens/calvincs/blob/rails3/spec/views/personnel/show.html.erb_spec.rb"&gt;&lt;code&gt;show.html.erb_spec.rb&lt;/code&gt;&lt;/a&gt;.  Instead, I call a bunch of partials (slightly modified here):&lt;/p&gt;&lt;pre&gt;
&amp;lt;div id="full_name_header"&amp;gt;
  &amp;lt;h1&amp;gt;&amp;lt;%= @user.full_name %&amp;gt;&amp;lt;/h1&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;%= render 'pages/image' %&amp;gt;
&amp;lt;%= render 'job_title' %&amp;gt;
&amp;lt;%= render 'contact_information' %&amp;gt;
&amp;lt;%= render 'education' %&amp;gt;
&amp;lt;%= render 'interests' %&amp;gt;
&amp;lt;%= render 'profile' %&amp;gt;
&lt;/pre&gt;&lt;p&gt;The partials can use the data in &lt;code&gt;@user&lt;/code&gt;, so there's no need to pass in any local variables.&lt;/p&gt;&lt;p&gt;To test this &lt;code&gt;show.html.erb&lt;/code&gt;, I only need to make sure that the partials are being rendered:&lt;/p&gt;&lt;pre&gt;
view.should_receive(:render).with('job_title').and_return("job title")
view.should_receive(:render).with('pages/image').and_return("image")
view.should_receive(:render).with('contact_information').and_return("contact")
view.should_receive(:render).with('education').and_return("education")
view.should_receive(:render).with('interests').and_return("interests")
view.should_receive(:render).with('profile').and_return("profile")
&lt;/pre&gt;&lt;p&gt;In specs for &lt;code&gt;_profile.html.erb&lt;/code&gt;, I can make sure that a profile section is generated (complete with a header) when the user has a profile, but generates nothing (not even a header) when &lt;code&gt;@user.profile&lt;/code&gt; is blank.&lt;/p&gt;&lt;p&gt;This creates a lot more files, but I find that a fair tradeoff for the simpler code and simpler tests.&lt;/p&gt;&lt;h3&gt;It's Broken!&lt;/h3&gt;&lt;p&gt;However, &lt;em&gt;mocking out &lt;code&gt;render&lt;/code&gt; is hopelessly broken in RSpec 2&lt;/em&gt;.  I understand why it's broken, and it's a really good reason, but I struggled with a solution.&lt;/p&gt;&lt;p&gt;It's broken because I have to call &lt;code&gt;render&lt;/code&gt; in order to execute the test.&lt;/p&gt;&lt;pre&gt;
it "should render" do
  view.should_receive(:render).with("some_partial").and_return("some result")
  render
end
&lt;/pre&gt;&lt;p&gt;I immediately get an expectation error: expected a call to &lt;code&gt;render&lt;/code&gt; with a bunch of arguments (i.e., &lt;code&gt;:partial =&gt; "some_partial"&lt;/code&gt;), but &lt;em&gt;got a call to &lt;code&gt;render&lt;/code&gt; with no arguments&lt;/em&gt;.  Yes, the call right in the spec there!  It's been mocked out!!!&lt;/p&gt;&lt;p&gt;Earlier versions of RSpec would actually help us mock out the recursive calls to &lt;code&gt;render&lt;/code&gt; and still let us make the call at the heart of the spec.  Unfortunately, this required knowledge and monkey patching of the Rails internals, and when those internals changed, RSpec would have to be updated.  I completely understand why the RSpec developers don't want to do this any more, so I'm not faulting them.&lt;/p&gt;&lt;p&gt;But I am struggling for a satisfying solution.&lt;/p&gt;&lt;h3&gt;Solution #1: Helper Methods&lt;/h3&gt;&lt;p&gt;On a Rails-3-from-scratch project, I discovered that many of these "Extract partials" were really better implemented as "Extract into helper method".  I'm then forced to pick a descriptive name which can easily be mocked.&lt;/p&gt;&lt;p&gt;So mocking becomes easy without any awkward changes:&lt;/p&gt;&lt;pre&gt;
user = mock_model(User)
assign(:user, user)
view.should_receive(:render_profile).with(user).and_return("profile")
render
&lt;/pre&gt;&lt;p&gt;The view just needs to call &lt;code&gt;render_profile(@user)&lt;/code&gt; to meet this expectation.&lt;/p&gt;&lt;p&gt;&lt;code&gt;render_profile&lt;/code&gt; itself lives in a helper module, and its specs live in the test file for that helper module.&lt;/p&gt;&lt;p&gt;One tip: pass in your full object to the helper method, not a component object.  For example, &lt;code&gt;render_profile(@user)&lt;/code&gt;, &lt;em&gt;not&lt;/em&gt;&lt;code&gt;render_profile(@user.profile)&lt;/code&gt;.  If I pass in the profile, I have to stub or mock that attribute in the view test; given enough helper methods for many attributes, all this mocking becomes tedious.  I haven't found this to be a problem in the helper methods.&lt;/p&gt;&lt;h3&gt;Solution #2: Create an Alias&lt;/h3&gt;&lt;p&gt;When I really want to call &lt;code&gt;render&lt;/code&gt; recursively (because there's a lot to render or because I'm already doing it that way), I defined this helper in &lt;code&gt;app/helpers/application_helper.rb&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;
def render2(*args)
  render(*args)
end
&lt;/pre&gt;&lt;p&gt;For the record: &lt;em&gt;I loathe this name.&lt;/em&gt;  I tried &lt;code&gt;render_rec&lt;/code&gt; for "render recursive", but that's worse.&lt;/p&gt;&lt;p&gt;All this does is set up &lt;code&gt;render2&lt;/code&gt; as an alias for &lt;code&gt;render&lt;/code&gt;.  (You can't use &lt;code&gt;alias&lt;/code&gt; because &lt;code&gt;render&lt;/code&gt; isn't always declared, like when you run your non-view specs.)&lt;/p&gt;&lt;p&gt;But now I can set these expectations:&lt;/p&gt;&lt;pre&gt;
view.should_receive(:render2).with('job_title').and_return("job title")
view.should_receive(:render2).with('pages/image').and_return("image")
view.should_receive(:render2).with('contact_information').and_return("contact")
view.should_receive(:render2).with('education').and_return("education")
view.should_receive(:render2).with('interests').and_return("interests")
view.should_receive(:render2).with('profile').and_return("profile")
&lt;/pre&gt;&lt;p&gt;And change the view to use &lt;code&gt;render2&lt;/code&gt; to satisfy these expectations.&lt;/p&gt;&lt;p&gt;As I mentioned, I really hate the name &lt;code&gt;render2&lt;/code&gt;.  But otherwise I find this to be a satisfactory solution, although I suspect that relying more on helper methods might be an even better solution.&lt;/p&gt;&lt;h3&gt;Next Time&lt;/h3&gt;&lt;p&gt;I upgrade Cucumber features and scenarios.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1530259284605417747?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1530259284605417747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1530259284605417747' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1530259284605417747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1530259284605417747'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part_20.html' title='Upgrading to Rails 3 and RSpec 2, Part 4b: Recursive Rendering'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5221759505130753059</id><published>2010-08-19T19:26:00.001-04:00</published><updated>2010-08-19T19:26:02.523-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='upgrading'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Upgrading to Rails 3 and RSpec 2, Part 4a: Views</title><content type='html'>&lt;p&gt;I continue my series on upgrading the RSpec examples for a Rails 3 app.  Today it's about testing the views.  (Previously: &lt;a href="http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-1.html"&gt;an introduction&lt;/a&gt;, &lt;a href="http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-2.html"&gt;controller specs&lt;/a&gt;, and &lt;a href="http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-3_15.html"&gt;router specs&lt;/a&gt;.)  I have a &lt;em&gt;lot&lt;/em&gt; to say about RSpec 2 and testing views, so I've had to split this up into two separate posts.&lt;/p&gt;&lt;p&gt;Many developers have strong opinions against testing views; other like to test them with their controllers.  I like testing views separate from controllers, and I try to test the rendered content, not the rendered look.  For example, here are some questions my specs try to answer: does the title of the book actually appear in the output?  is the title in an h1 header? does the book's authors appear? are the authors listed in the correct order?&lt;/p&gt;&lt;p&gt;In this post, I'll talk about these topics:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;how to refer to the template and the response in your spec (brand new names!);&lt;/li&gt;&lt;li&gt;how to assign values to instance variables for the view (&lt;em&gt;big&lt;/em&gt; change!);
  &lt;li&gt;how to render your template DRYly (with and without local variables); and&lt;/li&gt;&lt;li&gt;how to mock new records.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In my next post, I'll talk about recursive rendering.&lt;/p&gt;&lt;h3&gt;New Handles&lt;/h3&gt;&lt;p&gt;What you knew as &lt;code&gt;template&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; are now &lt;code&gt;view&lt;/code&gt; and &lt;code&gt;rendered&lt;/code&gt;, respectively:&lt;/p&gt;&lt;pre&gt;
it "should have a login link when no current user" do
  &lt;strong&gt;view&lt;/strong&gt;.should_receive(:current_user).and_return(nil)
  render
  &lt;strong&gt;rendered&lt;/strong&gt;.should have_selector("a", :href =&gt; login_path, :content =&gt; "log in")
end
&lt;/pre&gt;&lt;p&gt;A project-wide search-and-replace is a great way to upgrade.  Some tips:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Search for "template." and "response." (with a real period, not a regex period!) as your search terms.&lt;/li&gt;&lt;li&gt;Include the period on the replacement text, "view." and "rendered.".&lt;/li&gt;&lt;li&gt;Use &lt;code&gt;response&lt;/code&gt; in your controller, so be selective in what you change!&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I'm not sure why this change was made, but the new names make a bit more sense to me.&lt;/p&gt;&lt;h3&gt;Completely New Way to Assign Instance Variables&lt;/h3&gt;&lt;p&gt;Views make heavy use of instance variables set in the controller.  RSpec 1.x had an &lt;code&gt;assigns&lt;/code&gt; hash that you set before rendering:&lt;/p&gt;&lt;pre&gt;
# old RSpec 1.x code!
it "should display a title" do
  book = mock_model(Book, :title =&gt; "Dune")
  &lt;strong&gt;assigns[:book] = book&lt;/strong&gt;
  render
  response.should have_selector("h1", :content =&gt; "Dune")
end
&lt;/pre&gt;&lt;p&gt;This simulates assigning a (mocked) &lt;code&gt;book&lt;/code&gt; to the &lt;code&gt;@book&lt;/code&gt; variable in the view template.  In Rspec 2, there's an &lt;code&gt;assign(variable, value)&lt;/code&gt; method:&lt;/p&gt;&lt;pre&gt;
it "should display a title" do
  book = mock_model(Book, :title =&gt; "Dune")
  &lt;strong&gt;assign(:book, book)&lt;/strong&gt;
  render
  rendered.should have_selector("h1", :content =&gt; "Dune")
end
&lt;/pre&gt;&lt;p&gt;I'm not sure what the benefit of this change is, but it's a change you can't avoid.  The &lt;code&gt;view&lt;/code&gt; and &lt;code&gt;rendered&lt;/code&gt; changes are deprecations, but this is a show-stopper.  You'll have to change your assigned variables before the specs will run.  Unfortunately, a global search could help you find the code that must change, but a global replace will only help with part of the change.&lt;/p&gt;&lt;h3&gt;Render Without an Argument&lt;/h3&gt;&lt;p&gt;If you specify a full path to the template in the description of the &lt;code&gt;describe&lt;/code&gt; block, you do &lt;em&gt;not&lt;/em&gt; have to repeat it when you render the view for the spec.  For example:&lt;/p&gt;&lt;pre&gt;
describe &lt;strong&gt;"books/show.html.erb"&lt;/strong&gt; do
  it "should render" do
    render    # renders "book/show.html.erb"
  end
end
&lt;/pre&gt;&lt;p&gt;As a case of "Don't Repeat Yourself", this is a win.  Consider multiple &lt;code&gt;it&lt;/code&gt; blocks, each one rendering the same template.  It saves just a little bit of typing and reduces the risk of typing one of them wrong.  Better yet, if you were to refactor the code: rename the template or the controller, you have to change just the one description, not each call to &lt;code&gt;render&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;This may be an old feature of RSpec that I stumbled on.  I had been using abbreviated names for template like &lt;code&gt;"show"&lt;/code&gt; or &lt;code&gt;"books/show"&lt;/code&gt;.  When I did my Internet searches to find out why these weren't working, I discovered canonical examples which used &lt;code&gt;render&lt;/code&gt; without arguments.&lt;/p&gt;&lt;h3&gt;Render Without an Argument &lt;em&gt;with Locals&lt;/em&gt;&lt;/h3&gt;&lt;p&gt;Some views have local variables passed to them:&lt;/p&gt;&lt;pre&gt;
# in a controller
render "show", :locals =&gt; { :foo =&gt; value_for_foo }
&lt;/pre&gt;&lt;p&gt;To test this, I mock out &lt;code&gt;foo&lt;/code&gt; as a method call on the view:&lt;/p&gt;&lt;pre&gt;
it "should use the value in foo" do
  view.should_receive(:foo).any_number_of_times.and_return("rendered foo")
  render
  rendered.should contain("rendered foo")
end
&lt;/pre&gt;&lt;p&gt;If I don't mock the local variable this way, I have to specify the template and the local variable in the call to &lt;code&gt;render&lt;/code&gt;, but as I pointed out in the previous section, I don't want to mention the template.&lt;/p&gt;&lt;p&gt;There's an ambiguity in Ruby when an identifier seems to be used as a local variable: it could be a local variable, or it could actually be a method call to a method with no arguments.  (I've &lt;a href="http://jdfrens.blogspot.com/2007/05/parentheses-and-other-punctuation.html"&gt;blogged about this before&lt;/a&gt;.)  What's really wacky here is that the ambiguity persists throughout the app's execution up until each time &lt;code&gt;foo&lt;/code&gt; is evaluated.  It's a bit complicated to fully explain how this ambiguity is pulled off in Ruby, but suffice it to say that mocking out the local variable this way works just fine.&lt;/p&gt;&lt;p&gt;Just keep in mind that local variables are often called more than once, so using &lt;code&gt;any_number_of_times&lt;/code&gt; or &lt;code&gt;at_least(:once)&lt;/code&gt; is strongly advised.&lt;/p&gt;&lt;p&gt;The more I think about it, the more this should be abstracted out into a helper for the &lt;code&gt;spec_helper&lt;/code&gt; file:&lt;/p&gt;&lt;pre&gt;
def local_variable(variable, value)
  view.should_receive(variable).any_number_of_times.and_return(value)
end
...
local_variable(:foo, "rendered foo")
&lt;/pre&gt;&lt;p&gt;It's a bit more expressive.&lt;/p&gt;&lt;h3&gt;New Records&lt;/h3&gt;&lt;p&gt;When I render a form, I want to make sure my submission button indicates whether submitting the form will create new data ("Create Book") or update existing data ("Update Book").  I also wanted to make sure that the right RESTful method was being used (POST or PUT).  I used to stub &lt;code&gt;new_record?&lt;/code&gt; on my mock objects as appropriate.  That does not seem to be sufficient now, but there's an easy solution.&lt;/p&gt;&lt;p&gt;First, a mocked model is not new by default.  So objects that need to be updated are really easy to create!&lt;/p&gt;&lt;p&gt;Second, new objects are also easy to create when you know the right incantation:&lt;/p&gt;&lt;pre&gt;
book = mock_model(Book).as_new_record
&lt;/pre&gt;&lt;p&gt;This method might be old, but I was forced to discover it because my old tricks weren't working with RSpec 2.&lt;/p&gt;&lt;p&gt;It's worth pointing out that labeling the button with "Create" or "Update" is handled by Rails 3, so I'm slipping into testing Rails, not really my code.  But there are other situations where have a mocked model which thinks it's a new record is important.&lt;/p&gt;&lt;h3&gt;Next Time...&lt;/h3&gt;&lt;p&gt;Next time I'll look at the problem of mocking out recursive calls to &lt;code&gt;render&lt;/code&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5221759505130753059?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5221759505130753059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5221759505130753059' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5221759505130753059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5221759505130753059'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part.html' title='Upgrading to Rails 3 and RSpec 2, Part 4a: Views'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7837661222413844228</id><published>2010-08-18T16:56:00.001-04:00</published><updated>2010-08-18T16:56:52.673-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='parallel programming'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Parallel Programming the Functional Way</title><content type='html'>&lt;p&gt;I've got two presentations to recommend.  The first one I watched a few weeks ago, and it's an interesting watch to see how parallelism can be done in Haskell pretty easily.  The second presentation was cited by the first, and it's absolutely awesome&amp;mdash;and not just because it validates my dissertation!  I'm going to elaborate on the second presentation because it is a much more general conclusion and because it relates so well to the work that I've done.&lt;/p&gt;&lt;h3&gt;Multicore Programming in Haskell&lt;/h3&gt;&lt;p&gt;&lt;a href="http://www.infoq.com/presentations/Multicore-Programming-in-Haskell"&gt;"Multicore Programming in Haskell"&lt;/a&gt; (&lt;a href="http://www.haskell.org/~simonmar/multicore-haskell-marlow-qcon2010.pdf"&gt;PDF of slides&lt;/a&gt;) by Simon Marlow describes the how-to and how-done of parallel programming in Haskell.  As someone who's dabbled in Haskell programming in the past, this talk made me very interested in trying some more Haskell coding.&lt;/p&gt;&lt;p&gt;You can get a good idea of the content from the slides, but the talk itself is quite good.  I'd recommend it to someone familiar or just curious about Haskell.  If you're doing parallel programming you &lt;em&gt;should&lt;/em&gt; be interested in Haskell, and this talk will help you see why.&lt;/p&gt;&lt;h3&gt;Organizing Functional Code for Parallel Execution; or, foldl and foldr Considered Slightly Harmful&lt;/h3&gt;&lt;p&gt;Marlow cited &lt;a href="http://vimeo.com/6624203"&gt;"Organizing Functional Code for Parallel Execution; or, foldl and foldr Considered Slightly Harmful"&lt;/a&gt; (&lt;a href=""&gt;PDF of slides&lt;/a&gt;) by Guy Steele in his talk.  Again, you can get the feel for the content from the slides, but some of the slides are packed with very dense content (both code and prose).  The pacing of the talk helped me to digest the content better, and Guy Steele is just a great speaker, too.&lt;/p&gt;&lt;p&gt;Steele's concluding slide is this: "Get rid of cons!"  For those unfamiliar with LISP, this is translated as "Get rid of linked lists!"  For parallelism, we want balanced divide-and-conquer structures, not one-element-and-rest-of-structure.  For example, to compute the length of a list with linked lists, one would write this:&lt;p&gt;&lt;pre&gt;
length [] = 0
length (x : xs) = 1 + length xs
&lt;/pre&gt;&lt;p&gt;The expression &lt;code&gt;x:xs&lt;/code&gt; represents a linked-list node with the value &lt;code&gt;x&lt;/code&gt; as the value and &lt;code&gt;xs&lt;/code&gt; pointing to the rest of the list.  In LISP, we call this a &lt;strong&gt;cons box&lt;/strong&gt; (&lt;code&gt;:&lt;/code&gt; is the cons operator in Haskell).&lt;/p&gt;&lt;p&gt;We're forced to compute the length of the list element by element through the list, one after the other.  There's no parallelizing this.&lt;/p&gt;&lt;p&gt;But if we change the representation a bit:&lt;/p&gt;&lt;pre&gt;
length EmptyList = 0
length (SingletonList x) = 1
length (BinaryList left right) = length left + length right
&lt;/pre&gt;&lt;p&gt;We worry about three cases: empty, singleton, and recursive split.  In this case, the two recursive calls to &lt;code&gt;length&lt;/code&gt; could be done in parallel.  Further recursive calls can also be done in parallel.  If the splitting is done evenly, the height of the parallel execution tree drops from linear to logarithmic.&lt;/p&gt;&lt;p&gt;My dissertation research involved the recursive decomposition of matrices into quadtrees.  A one dimensional structure (a linked list or array) turns into a binary tree with two branches at the recursive case; a two dimensional structure (a matrix, a two-dimensional array) has a four-way branching in the recursive case.&lt;/p&gt;&lt;p&gt;What I found interesting is that my research reenforced Steele's observations and conclusions.  Almost as an aside, he mentioned that this recursive decomposition results in three cases: an empty case, a singleton case, and a recursive case.  Quadtrees have a zero matrix, a scalar matrix, and a recursive quadtree.  Observation reenforced.&lt;/p&gt;&lt;p&gt;I can also reenforce Steele's engineering optimization on Slide 73:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Optimized representations of singleton lists.&lt;/strong&gt;  My singleton case was a scalar value (a double-precision floating-point number) in an array.  That's about as optimized as one can get!&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Use tree branching factors larger than 2.&lt;/strong&gt;  It was really useful for me to split my matrices into four subtrees (although any power of four would work).  Larger branching factors means more parallelism earlier in the computation but at a cost of extra complexity.  (It would be interesting to see if the extra complexity could be handle by a program transformation by a compiler or interpreter.)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Use self-balancing trees (2-3, red-black, ﬁnger trees, . . . ).&lt;/strong&gt; I sort of had this.  Matrices would get padded out with zeros to make the number of rows and columns a power of two, then the quadtree splitting could be carried out very nicely.  There was never more than a logarithmic number of zeros to deal with, so they didn't cause too much of a problem overall, but some quadrants had more zeros than others (at the top of the representation).  The extra zeros made balancing the parallel dispatches quite interesting, but once an algorithm had a dense quadrant, it could really crank out computations in parallel.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Use sequential techniques near the leaves.&lt;/strong&gt;  Yes!!!!  This is to keep the processors pipeline as busy as possible with real computations (not computations for navigating the data structure).  My advisor worked &lt;em&gt;a lot&lt;/em&gt; on this.  He unfolded and re-rolled the singleton base cases, turning the general recursion into &lt;code&gt;for&lt;/code&gt; loops and &lt;code&gt;switch&lt;/code&gt; statements.  (We didn't consider this cheating since compilers should be able to make these transformations for us.)  It helped us keep our FLOPS level up.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Have arrays at the leaves. Decide dynamically whether to
process them sequentially or by parallel recursive subdivision.&lt;/strong&gt; This is an issue of contiguous memory, and Steele is absolutely right.  His &lt;code&gt;conc&lt;/code&gt; boxes (which are just re-interpreted &lt;code&gt;cons&lt;/code&gt; boxes) is a linked structure, and this can kill cache coherency when you get to the leaves.  In my research, I worked with a contiguous chunk of memory and superimposed a tree structure above it, so I already had arrays in contiguous memory at the leaves.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;When iterating over an integer range, decide dynamically
whether to process it sequentially or by parallel recursive
subdivision.&lt;/strong&gt; Never applied to me, but it's wise council.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Overall, this is a great talk, and if you're not using data structures that support parallelism with recursive decomposition (and you think you're doing parallel programming), you have to give this approach a try.  This talk may not convince you (especially because the examples get so dense in the end), but it'll give you a place to start.&lt;/p&gt;&lt;p&gt;And if the &lt;a href="http://projectfortress.sun.com/Projects/Community"&gt;Fortress&lt;/a&gt; code examples scare you, meditate on them for a while, and come back to them later.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7837661222413844228?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7837661222413844228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7837661222413844228' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7837661222413844228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7837661222413844228'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/parallel-programming-functional-way.html' title='Parallel Programming the Functional Way'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8438468894940635788</id><published>2010-08-16T15:03:00.001-04:00</published><updated>2010-08-16T15:03:37.467-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Use Prerelease Mongrel with Rails 3 Release Candidate and Ruby 1.9.2</title><content type='html'>&lt;p&gt;The official, stable release of Mongrel seems to work fine with Rails 3 and Ruby 1.8.7.  On one of my projects, I'm using Rails 3 with Ruby 1.9.2, and then you need the prerelease of Mongrel:&lt;/p&gt;&lt;pre&gt;
gem "mongrel", "&gt;= 1.2.0.pre2"
&lt;/pre&gt;&lt;p&gt;For Google searches, here are the errors I got without the prerelease version:&lt;/p&gt;&lt;pre&gt;
Installing mongrel (1.1.5) with native extensions /Users/jdfrens/.rvm/rubies/ruby-1.9.2-rc2/lib/ruby/1.9.1/rubygems/installer.rb:483:in `rescue in block in build_extensions': ERROR: Failed to build gem native extension. (Gem::Installer::ExtensionBuildError)

/Users/jdfrens/.rvm/rubies/ruby-1.9.2-rc2/bin/ruby extconf.rb 
checking for main() in -lc... yes
creating Makefile

make
gcc -I. -I/Users/jdfrens/.rvm/rubies/ruby-1.9.2-rc2/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/jdfrens/.rvm/rubies/ruby-1.9.2-rc2/include/ruby-1.9.1/ruby/backward -I/Users/jdfrens/.rvm/rubies/ruby-1.9.2-rc2/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE   -fno-common -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long  -fno-common -pipe  -o http11.o -c http11.c
http11.c: In function ‘http_field’:
http11.c:70: warning: format not a string literal and no format arguments
http11.c:71: warning: format not a string literal and no format arguments
http11.c:77: error: ‘struct RString’ has no member named ‘ptr’
http11.c:77: error: ‘struct RString’ has no member named ‘len’
http11.c:77: warning: left-hand operand of comma expression has no effect
http11.c: In function ‘request_uri’:
http11.c:102: warning: format not a string literal and no format arguments
http11.c: In function ‘fragment’:
http11.c:113: warning: format not a string literal and no format arguments
http11.c: In function ‘request_path’:
http11.c:124: warning: format not a string literal and no format arguments
http11.c: In function ‘query_string’:
http11.c:135: warning: format not a string literal and no format arguments
http11.c: In function ‘header_done’:
http11.c:172: error: ‘struct RString’ has no member named ‘ptr’
http11.c:174: error: ‘struct RString’ has no member named ‘ptr’
http11.c:176: error: ‘struct RString’ has no member named ‘ptr’
http11.c:177: error: ‘struct RString’ has no member named ‘len’
http11.c: In function ‘HttpParser_execute’:
http11.c:298: error: ‘struct RString’ has no member named ‘ptr’
http11.c:299: error: ‘struct RString’ has no member named ‘len’
http11.c:307: warning: format not a string literal and no format arguments
make: *** [http11.o] Error 1
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8438468894940635788?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8438468894940635788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8438468894940635788' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8438468894940635788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8438468894940635788'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/use-prerelease-mongrel-with-rails-3.html' title='Use Prerelease Mongrel with Rails 3 Release Candidate and Ruby 1.9.2'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5096554792514254663</id><published>2010-08-15T21:20:00.001-04:00</published><updated>2010-08-15T21:21:19.234-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='upgrading'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Upgrading to Rails 3 and RSpec 2, Part 3: Router</title><content type='html'>&lt;p&gt;I my continuing series about upgrading RSpec for Rails 3 (previously: &lt;a href="http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-1.html"&gt;"Part 1: Introduction"&lt;/a&gt; and &lt;a href="http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-2.html"&gt;"Part 2: Controllers"&lt;/a&gt;).  Today, it's testing my routes.&lt;/p&gt;&lt;p&gt;But first, I finally pushed my rails3 branch to github.  You can easily compare &lt;a href="http://github.com/jdfrens/calvincs/compare/last-rails2...rails3"&gt;the last Rails 2 version and the first useful Rails 3 version&lt;/a&gt; with Github's awesome comparison view.&lt;/p&gt;&lt;h3&gt;The New DSL&lt;/h3&gt;&lt;p&gt;It's awesome.  I find it much more expressive.  Here are some resources if to help you with the upgrade on the Rails side:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/"&gt;"The Rails 3 Router: Rack It Up"&lt;/a&gt; by Yehuda Katz&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/"&gt;"The Lowdown on Routes in Rails 3"&lt;/a&gt; by Rizwan Reza.&lt;/li&gt;&lt;li&gt;&lt;a href="http://guides.rubyonrails.org/routing.html"&gt;"Rails Routing from the Outside In"&lt;/a&gt; from the RailsGuides.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I used the second and third resources a lot in my upgrade.  I include the first resource because it got me excited about the changes in the first place.&lt;/p&gt;&lt;h3&gt;&lt;code&gt;:as&lt;/code&gt; versus &lt;code&gt;:path&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;For some reason, I didn't find the difference between these two settings as clear as I would have liked from those resources.&lt;/p&gt;&lt;p&gt;&lt;code&gt;:path&lt;/code&gt; changes the path used to access a resource.  For example:&lt;/p&gt;&lt;pre&gt;
resources :pages, :path =&gt; "p"
&lt;/pre&gt;&lt;p&gt;The path to access the "pages" resource is &lt;code&gt;/p&lt;/code&gt;, not &lt;code&gt;/pages&lt;/code&gt;.  I test this with specs like this:&lt;/p&gt;&lt;pre&gt;
it "should recognize page routes" do
  { :get =&gt; "/p/foo" }.should route_to(
      :controller =&gt; "pages", 
      :action =&gt; "show", 
      :id =&gt; 'foo')
end

it "should use /p abbreviation path to a page" do
  page = Factory.build(:page, :identifier =&gt; "foobar")
  page_path(page).should == "/p/foobar"
end
&lt;/pre&gt;&lt;p&gt;&lt;code&gt;:as&lt;/code&gt; changes the name by which you refer to the resource (or route) in your app.  I use this only for some simple routes:&lt;/p&gt;&lt;pre&gt;
match '/users/login' =&gt; 'users#login', :as =&gt; :login
match '/users/logout' =&gt; 'users#logout', :as =&gt; :logout
&lt;/pre&gt;&lt;p&gt;This results in helpers like &lt;code&gt;login_path&lt;/code&gt; and &lt;code&gt;logout_url&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Testing a Route&lt;/h3&gt;&lt;p&gt;The old techniques for testing a route with RSpec seem to be gone.  Instead, they should use a &lt;code&gt;route_to&lt;/code&gt; matcher as seen in the first spec above.&lt;/p&gt;&lt;p&gt;In addition to testing my &lt;code&gt;:path&lt;/code&gt; setting, I also recognize pages by their identifier, not the id number that's assigned by the database.  My RSpec spec demonstrates and ensures these features.&lt;p&gt;&lt;p&gt;I don't actually test &lt;em&gt;every&lt;/em&gt; route since it begins to feel like testing Rails instead of testing my app.  This spec is good because I've overridden some defaults.&lt;/p&gt;&lt;h3&gt;Testing &lt;code&gt;_url&lt;/code&gt; and &lt;code&gt;_path&lt;/code&gt; Helpers&lt;/h3&gt;&lt;p&gt;Because of the changes I made to the defaults for routing "pages", I also wanted to test the &lt;code&gt;pages_path&lt;/code&gt; and &lt;code&gt;page_path(@page)&lt;/code&gt; helper methods as seen in the second spec above.&lt;/p&gt;&lt;p&gt;I discovered that the new standard for testing routes is to put the spec file(s) in a &lt;code&gt;spec/routing&lt;/code&gt; subdirectory.  When I did this, I got "&lt;code&gt;page_path&lt;/code&gt; method undefined" errors.  So I moved my tests back to the &lt;code&gt;spec/controllers&lt;/code&gt; folder.  I don't have &lt;em&gt;that&lt;/em&gt; many routes to check, so moving them to another folders isn't so urgent to me.&lt;/p&gt;&lt;h3&gt;Next Time...&lt;/h3&gt;&lt;p&gt;Next time we'll look at the significant and frustrating changes to testing views.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5096554792514254663?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5096554792514254663/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5096554792514254663' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5096554792514254663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5096554792514254663'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-3_15.html' title='Upgrading to Rails 3 and RSpec 2, Part 3: Router'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1412749476692534524</id><published>2010-08-12T18:17:00.001-04:00</published><updated>2010-08-12T18:17:06.331-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='upgrading'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Upgrading to Rails 3 and RSpec 2, Part 2: Controllers</title><content type='html'>&lt;p&gt;In &lt;a href="http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-1.html"&gt;Part 1&lt;/a&gt;, I pointed out some resources to upgrade a Rails app to Rails 3.  In this part, I'm going to talk about the some of the changes I had to make to my controllers and their specs.&lt;/p&gt;&lt;p&gt;One important suggestion: &lt;em&gt;run just the controller specs with &lt;code&gt;rake spec:controllers&lt;/code&gt;&lt;/em&gt;.&lt;/p&gt;&lt;h3&gt;Arel in Controllers&lt;/h3&gt;&lt;p&gt;I still have to go through and switch to &lt;a href="http://github.com/rails/arel"&gt;Arel&lt;/a&gt; (or is it "ARel"?).  I don't anticipate problems with this.  Check out these resources if you'd like to know more:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://m.onkey.org/2010/1/22/active-record-query-interface"&gt;"Active Record Query Interface 3.0"&lt;/a&gt; by Pratik Naik at the &lt;a href="http://m.onkey.org/"&gt;"has_many :bugs, :through =&gt; :rails"&lt;/a&gt; blog.&lt;/li&gt;&lt;li&gt;&lt;a href="http://railscasts.com/episodes/202-active-record-queries-in-rails-3"&gt;"Active Record Queries in Rails 3"&lt;/a&gt; a Railscast by Ryan Bates.&lt;/li&gt;&lt;li&gt;&lt;a href="http://railscasts.com/episodes/215-advanced-queries-in-rails-3"&gt;"Advanced Queries in Rails 3"&lt;/a&gt; another Railscast from Ryan Bates.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Since I use a lot of mocking in my controllers, I imagine I'll have to make more than a few changes, but I also anticipate they'll all be straightforward.  (I'll be sure to let you know if they aren't.)&lt;/p&gt;&lt;h3&gt;Integer Params in Controller Specs&lt;/h3&gt;&lt;p&gt;To serve up the appropriate object, an action like show or edit has you finding the object by id:&lt;/p&gt;&lt;pre&gt;
it "should find image to edit" do
  image = mock_model(Image)
  Image.should_receive(:find).with(&lt;strong&gt;image.id&lt;/strong&gt;).and_return(image)
  get :edit, { :id =&amp;gt; &lt;strong&gt;image.id&lt;/strong&gt; }, user_session(:edit)
  assigns[:image].should == image
end
&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;image.id&lt;/code&gt; (an &lt;code&gt;Integer&lt;/code&gt;) in the &lt;code&gt;Image.find&lt;/code&gt; expectation used to be &lt;code&gt;image.id.to_s&lt;/code&gt; because Rails (or the RSpec framework) would massage the data values in the &lt;code&gt;params&lt;/code&gt; hash into strings.  It appears that this data conversion doesn't happen any more.  It works fine the way I have it above; it also works if both calls to &lt;code&gt;image.id&lt;/code&gt; are changed to &lt;code&gt;image.id.to_s&lt;/code&gt;; it fails if only one is changed.&lt;/p&gt;&lt;p&gt;I'm still debating what's better.  Using strings seems more honest, but is it really necessary?  I'm probably going to keep it simple without the &lt;code&gt;to_s&lt;/code&gt; conversion, but if this causes problems later on, I'm willing to switch.&lt;/p&gt;&lt;h3&gt;Params in Unhappy-Path Tests&lt;/h3&gt;&lt;p&gt;In the spec above, the call to &lt;code&gt;user_session(:edit)&lt;/code&gt; is a helper method to set up a session with an editor logged in.  Only editors get to edit images.  But what if some random guest tries editing an image?  I make sure the app redirects to the login page:&lt;/p&gt;&lt;pre&gt;
it "should redirect when not logged in" do
  get :edit, { :id =&gt; 1234 }
  response.should redirect_to(login_path)
end
&lt;/pre&gt;&lt;p&gt;If you are using only &lt;a href="http://guides.rubyonrails.org/routing.html#restful-routing-the-rails-default"&gt;RESTful routes&lt;/a&gt;, then you &lt;em&gt;must&lt;/em&gt; to include an &lt;code&gt;:id&lt;/code&gt; entry in the &lt;code&gt;params&lt;/code&gt; hash.  The &lt;code&gt;:id&lt;/code&gt; is used by the router to find the appropriate route.&lt;/p&gt;&lt;p&gt;If you include the default route (with or without RESTful routes), then the router will route &lt;code&gt;get :edit&lt;/code&gt; to the right place &lt;em&gt;even without an &lt;code&gt;:id&lt;/code&gt;&lt;/em&gt;.  Since the &lt;code&gt;params[:id]&lt;/code&gt; is ignored when you're not logged in, it seemed like a nice simplification.&lt;/p&gt;&lt;p&gt;I started my app before RESTful routes were a Thing, and apparently when I switched to RESTful routes, I didn't drop the default route until now, and this issue bit me.  It's not hard to fix: include the &lt;code&gt;:id&lt;/code&gt; even when &lt;code&gt;params[:id]&lt;/code&gt; is ignored for &lt;code&gt;show&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, and &lt;code&gt;destroy&lt;/code&gt; actions.&lt;/p&gt;&lt;h3&gt;Next Time...&lt;/h3&gt;&lt;p&gt;In my next article, I'll describe some of the issues I ran into with setting up and testing my router.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1412749476692534524?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1412749476692534524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1412749476692534524' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1412749476692534524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1412749476692534524'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-2.html' title='Upgrading to Rails 3 and RSpec 2, Part 2: Controllers'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2765051609223435873</id><published>2010-08-10T19:17:00.001-04:00</published><updated>2010-08-15T20:36:45.291-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='upgrading'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Upgrading to Rails 3 and RSpec 2, Part 1: Introduction</title><content type='html'>&lt;p&gt;Over the last couple of days I've been upgrading &lt;a href="http://github.com/jdfrens/calvincs"&gt;a Rails app&lt;/a&gt; from 2.3.8 to the 3.0 release candidate.  (&lt;strong&gt;Update, August 15:&lt;/strong&gt; see the &lt;a href="http://github.com/jdfrens/calvincs/tree/rails3"&gt;Rails 3 branch&lt;/a&gt; itself and &lt;a href="http://github.com/jdfrens/calvincs/compare/last-rails2...rails3"&gt;a comparison of the Rails 3 branch with the last Rails 2 version&lt;/a&gt;.)  The web has plenty of useful resources for Rails 3 itself and Rails 3 upgrading, but there's little to nothing on upgrading RSpec and Cucumber.  I'm going to write a few posts outlining what I did in my upgrade, concentrating on RSpec and Cucumber upgrades since Rails 3 itself is covered so well.&lt;/p&gt;&lt;p&gt;First, you have get the upgrade itself going.  I recommend:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Build a Rails 3 app from scratch.&lt;/strong&gt;  It really helped to know how a Rails 3 app was &lt;em&gt;supposed&lt;/em&gt; to look and work.  I started a whole new project, but a toy app (e.g., a blogging system or to-do list) would be just as good.  (Work through the &lt;a href="http://railstutorial.org/book"&gt;&lt;i&gt;Ruby on Rails Tutorial&lt;/i&gt;&lt;/a&gt; by Michael Hartl.)  Just make sure to build the app honestly: including tests!  It would also help to experiment with gems and plugins you use on other projects.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Watch Railscasts.&lt;/strong&gt;  Ryan Bates does a fantastic job every week in his &lt;a href="http://railscasts.com/"&gt;Railscasts&lt;/a&gt; screencasts.  The last two weeks he's done screencasts on upgrading to Rails 3:
	&lt;ul&gt;&lt;li&gt;&lt;a href="http://railscasts.com/episodes/225-upgrading-to-rails-3-part-1"&gt;Part 1&lt;/a&gt; is on the upgrade itself: creating a Gemfile, installing the plugin, re-generating the app.&lt;/li&gt;&lt;li&gt;&lt;a href="http://railscasts.com/episodes/226-upgrading-to-rails-3-part-2"&gt;Part 2&lt;/a&gt; is on upgrading the RSpec specs.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Use the plugin.&lt;/strong&gt;  The &lt;a href="http://github.com/rails/rails_upgrade"&gt;rails_upgrade plugin&lt;/a&gt; is great.  It shows many false positives on my project, but it's not difficult to get past them.  The rake tasks the plugin provide are pretty self-explanatory; but if you want to see a useful workflow with the plugin, Ryan Bates shows how to install and use the plugin in the Railscasts listed above.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The first Railscast episode on the Rails 3 upgrade is by far the most important resource I've listed here.  You can probably find the same information on any number of blogs as well.&lt;/p&gt;&lt;p&gt;I used Jeremy McAnally's &lt;a href="http://www.railsupgradehandbook.com/"&gt;&lt;i&gt;Rails 3 Upgrade Handbook&lt;/i&gt;&lt;/a&gt;, and I cannot recommend it completely.  If you've completely ignored Rails 3 up to this point, the handbook would be &lt;em&gt;great&lt;/em&gt; for you.  I've read many blog posts and watched &lt;em&gt;many&lt;/em&gt; presentations by Yehuda Katz, so I didn't need to know changes I was upgrading through.  If you're familiar with Rails already and the changes in Rails 3, then the Railscasts listed above are more than sufficient.  (Of course, this doesn't mean you can't buy the handbook anyway to "give back to the community"; McAnally did write the plugin!)&lt;/p&gt;&lt;p&gt;In my next post, I'll describe the changes I had to make to my controllers and controller specs.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2765051609223435873?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2765051609223435873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2765051609223435873' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2765051609223435873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2765051609223435873'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/08/upgrading-to-rails-3-and-rspec-2-part-1.html' title='Upgrading to Rails 3 and RSpec 2, Part 1: Introduction'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3573634566214785473</id><published>2010-07-30T14:53:00.001-04:00</published><updated>2010-07-30T14:53:56.348-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='awesome'/><title type='text'>Tab Candy for Firefox</title><content type='html'>&lt;p&gt;It's a bad name because it's &lt;em&gt;not&lt;/em&gt; just about making things look good.  "Tabs on Steroids" would be better.  Whatever we call it, it looks awesome.&lt;/p&gt;&lt;p&gt;&lt;a href="http://azarask.in/projects/tabcandy/"&gt;Tab Candy&lt;/a&gt; is a way of organizing tabs in the Firefox browser.  You create groups of tabs, and Firefox will show you just one group at a time.  I might create groups for "Communication" (with GMail, Reader, Facebook, and LinkedIn tabs), for "Hobbes Compiler" (with tabs open to the Java API and Parrot PIR references), for "Rails Project" (with tabs open to my development server and to references for Ruby, Rails, MongoDB, and MongoMapper), etc.  When I want to do email, I open up the "Communication" group, and my current tabs are replaced by Gmail, Reader, Facebook, and LinkedIn tabs.  When I want to go back to work on my Hobbes compiler, I switch that group, and its tabs replace the "Communication" tabs.&lt;/p&gt;&lt;p&gt;I tend to work with many tabs open at a time (right now I have 14 open), although I tend to organize them into separate windows (right now I have 1 open and 2 minimized).  The separate windows aren't a good organizational tool, but Tab Candy offers two &lt;em&gt;huge&lt;/em&gt; benefits over separate windows: named groups and spatial identities.  Just like a folder, a group can be given a name.  Can you imagine navigating a file system without named folders?  It's a simple feature that's incredibly powerful.  Being able to place those folders in a particular place is also very powerful.  A friend of mine in grad school did some research on Netscape's buttons on its toolbar.  (This was in the mid 1990s, so Netscape was cutting edge.)  It turned out that the size of the buttons, the icons on the buttons, and the words on the buttons did not matter nearly as much as the &lt;em&gt;location&lt;/em&gt; of the buttons.  Once users got use to Netscape, you could tweak the icons and text, and the users would still be as productive, but if you changed the order, the users would have to spend extra time finding right button.&lt;/p&gt;&lt;p&gt;Tab Candy is presently in alpha testing/release, but they promise more features (in meh-to-cool-to-awesome order):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Colors and background images for decorating your groups.  (While names and spatial position are essential, some decoration can help.)&lt;/li&gt;&lt;li&gt;Share tab groups in various ways.&lt;/li&gt;&lt;li&gt;Save tabs for later.  (Presumably this would unload these tabs from memory preventing Firefox from bloating.)&lt;/li&gt;&lt;li&gt;Search your tabs.&lt;/li&gt;&lt;li&gt;Multiple profiles so that you can log onto the same website with different logins.  (As a developer, this is &lt;em&gt;very&lt;/em&gt; appealing.)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I can't resist pointing you at this video for more information:&lt;/p&gt;&lt;object width="400" height="300"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=13560319&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=13560319&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;p&gt;&lt;a href="http://vimeo.com/13560319"&gt;An Introduction to Firefox's Tab Candy&lt;/a&gt; from &lt;a href="http://vimeo.com/user532161"&gt;Aza Raskin&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Strangely, Tab Candy is being presented as a new "OS-like interface".  I suppose, but here's my question: is Tab Candy more like the folder/file structure that you see in the Mac OS X Finder or like the virtual screens of Spaces on Mac OS X?  Of course, the answer is "both", but then what's the blend?  Or is there a better metaphor?&lt;/p&gt;&lt;p&gt;Tab Candy looks really cool; the only problem is that I'm presently a Google Chrome user.  Might Tab Candy be the feature to bring me back to Firefox?&lt;/p&gt;&lt;p&gt;(via &lt;a href="http://www.zdnet.com/blog/btl/firefoxs-next-big-innovation-a-new-os-like-interface/37277"&gt;ZDNet&lt;/a&gt;, via &lt;a href="http://www.dzone.com/links/firefoxs_next_big_innovation_a_new_oslike_interfa.html"&gt;DZone&lt;/a&gt;)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3573634566214785473?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3573634566214785473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3573634566214785473' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3573634566214785473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3573634566214785473'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/07/tab-candy-for-firefox.html' title='Tab Candy for Firefox'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2402449750321470299</id><published>2010-07-28T17:01:00.001-04:00</published><updated>2010-07-28T17:01:02.209-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='upgrading'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>"Calling a method in Rails::Application is deprecated..."</title><content type='html'>&lt;p&gt;I already described &lt;a href="http://jdfrens.blogspot.com/2010/07/but-i-am-using-new-routing-dsl.html"&gt;how I got rid of a DEPRECATION WARNING when upgrading from a Rails 3 beta to the latest release candidate&lt;/a&gt;.  That DEPRECATION WARNING involved the router DSL, and I'd like to point out that the &lt;em&gt;Rails 3 generator&lt;/em&gt; (from a beta release) generated the &lt;code&gt;map&lt;/code&gt; parameter for me.&lt;/p&gt;&lt;p&gt;Similarly, the Rails 3 generator is responsible for this DEPRECATION WARNING:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;DEPRECATION WARNING: Calling a method in Rails::Application is deprecated, please call it directly in your application constant Reviews::Application. (called from method_missing at /Users/jdfrens/.rvm/gems/ruby-1.9.2-rc2@Reviews/gems/railties-3.0.0.rc/lib/rails/application.rb:77)&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I love how it tells me where the deprecation is reported, not where it's committed.  (Stack trace, anyone?)  Instead it was a guessing game (after Google searches failed) to discover that the &lt;code&gt;Rakefile&lt;/code&gt; in the app's root directory is at fault.  Change this:&lt;/p&gt;&lt;pre&gt;&lt;strong&gt;Rails&lt;/strong&gt;::Application.load_tasks
&lt;/pre&gt;&lt;p&gt;to this:&lt;/p&gt;&lt;pre&gt;&lt;strong&gt;Reviews&lt;/strong&gt;::Application.load_tasks
&lt;/pre&gt;&lt;p&gt;Of course, use the name of your own app, not "&lt;code&gt;Reviews&lt;/code&gt;".&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2402449750321470299?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2402449750321470299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2402449750321470299' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2402449750321470299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2402449750321470299'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/07/method-in-railsapplication-is.html' title='&amp;quot;Calling a method in Rails::Application is deprecated...&amp;quot;'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7624877091708181944</id><published>2010-07-26T18:56:00.001-04:00</published><updated>2010-07-26T18:56:37.140-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='upgrading'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>But I Am Using the New Routing DSL!!!</title><content type='html'>&lt;p&gt;I upgraded a Rails 3 app to the &lt;a href="http://weblog.rubyonrails.org/2010/7/26/rails-3-0-release-candidate"&gt;first release candidate&lt;/a&gt;.  I got this error running my tests:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;DEPRECATION WARNING: You are using the old router DSL which will be removed in Rails 3.1. Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I've been very careful to use the new DSL, so this kind of disappointed me.  What could I possibly be doing wrong?  I tried commenting out various directives in the &lt;code&gt;routes.rb&lt;/code&gt; file, but I kept getting the warning.  Then I changed this:&lt;/p&gt;&lt;pre&gt;
Reviews::Application.routes.draw do |map|
&lt;/pre&gt;

to this:

&lt;pre&gt;
Reviews::Application.routes.draw do
&lt;/pre&gt;&lt;p&gt;Deprecation warning all gone.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7624877091708181944?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7624877091708181944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7624877091708181944' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7624877091708181944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7624877091708181944'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/07/but-i-am-using-new-routing-dsl.html' title='But I Am Using the New Routing DSL!!!'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8737724380969975943</id><published>2010-07-26T18:21:00.001-04:00</published><updated>2010-07-26T18:21:50.834-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='coroutines'/><category scheme='http://www.blogger.com/atom/ns#' term='continuations'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>More Fibers for Rails</title><content type='html'>&lt;p&gt;I have to recommend yet another video talk: &lt;a href="http://www.viddler.com/explore/GreggPollack/videos/40/"&gt;"No Callbacks, No Threads &amp; Ruby 1.9" &lt;/a&gt;by &lt;a href="http://igvita.com/"&gt;Ilya Grigorik&lt;/a&gt;&lt;/p&gt;&lt;object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="437" height="370" id="viddler_cfadc37f"&gt;&lt;param name="movie" value="http://www.viddler.com/player/cfadc37f/" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;embed src="http://www.viddler.com/player/cfadc37f/" width="437" height="370" type="application/x-shockwave-flash" allowScriptAccess="always" allowFullScreen="true" name="viddler_cfadc37f"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;p&gt;Basically, the idea is to use &lt;a href="http://ruby-doc.org/core-1.9/classes/Fiber.html"&gt;Fibers&lt;/a&gt; to implement concurrency in existing frameworks (with minimal, behind-the-scenes changes), and you get to write the code you want.  I'm thinking that Fibers could be quite useful...&lt;/p&gt;&lt;p&gt;I mastered &lt;a href="http://en.wikipedia.org/wiki/Call-with-current-continuation"&gt;&lt;code&gt;call/cc&lt;/code&gt;&lt;/a&gt; back in grad school (at least to get me through one test), but I didn't do much with &lt;a href="http://en.wikipedia.org/wiki/Coroutine"&gt;coroutines&lt;/a&gt;.  Fibers are closer to coroutines, and fortunately that makes them easier to pick up.&lt;/p&gt;&lt;p&gt;Here are some Fiber-related articles to get familiar with Fibers before watching this video:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://pragdave.blogs.pragprog.com/pragdave/2007/12/pipelines-using.html"&gt;"Pipelines Using Fibers in Ruby 1.9"&lt;/a&gt; by Dave Thomas&lt;/li&gt;&lt;li&gt;&lt;a href="http://pragdave.blogs.pragprog.com/pragdave/2008/01/pipelines-using.html"&gt;"Pipelines Using Fibers in Ruby 1.9&amp;mdash;Part II"&lt;/a&gt; by Dave Thomas&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.infoq.com/news/2007/08/ruby-1-9-fibers"&gt;"Ruby 1.9 adds Fibers for lightweight concurrency"&lt;/a&gt; by Werner Schuster at InfoQ&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;(via Gregg Pollack on the &lt;a href="http://blog.envylabs.com/2010/07/no-callbacks-no-threads-ruby-1-9/"&gt;EnvyLabs blog&lt;/a&gt;)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8737724380969975943?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8737724380969975943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8737724380969975943' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8737724380969975943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8737724380969975943'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/07/more-fibers-for-rails.html' title='More Fibers for Rails'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8433762849228737049</id><published>2010-07-24T19:32:00.001-04:00</published><updated>2010-07-24T19:32:56.878-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='recommendation'/><category scheme='http://www.blogger.com/atom/ns#' term='parrot'/><title type='text'>Parrot (PIR) Tutorial</title><content type='html'>&lt;p&gt;I stumbled on a nifty tutorial on programming in &lt;a href="http://www.parrot.org/"&gt;Parrot&lt;/a&gt;, the virtual machine for &lt;a href="http://dev.perl.org/perl6/"&gt;Perl 6&lt;/a&gt;: &lt;a href="http://coolnamehere.com/geekery/parrot/learn/index.html"&gt;"Parrot Babysteps"&lt;/a&gt; by &lt;a href="http://coolnamehere.com/brian/index.html"&gt;Brian Wisti&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You get variable/register basics, data types (&lt;code&gt;int&lt;/code&gt;s, &lt;code&gt;float&lt;/code&gt;s, and strings), data structures (arrays which act as stacks and queues and iterators), and basic control structures (i.e., &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;goto&lt;/code&gt;).  By the end of the tutorial, Wisti does some file I/O.  I would have preferred to know more about &lt;a href="http://docs.parrot.org/parrot/latest/html/docs/book/pir/ch07_objects.pod.html"&gt;PMCs and method dispatch&lt;/a&gt; (especially &lt;a href="http://docs.parrot.org/parrot/devel/html/docs/pdds/pdd27_multiple_dispatch.pod.html"&gt;multiple dispatch&lt;/a&gt;), but then I'm not the one writing the tutorial.  Wisti does a really good job, and I wish I'd had this when I was teaching my Programming Languages course.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8433762849228737049?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8433762849228737049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8433762849228737049' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8433762849228737049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8433762849228737049'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/07/parrot-pir-tutorial.html' title='Parrot (PIR) Tutorial'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3884195844662217334</id><published>2010-07-21T17:28:00.001-04:00</published><updated>2010-07-21T17:28:13.774-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>String, StringBuilder, StringBuilder, and Performance</title><content type='html'>&lt;p&gt;Earlier today I came across as article &lt;a href="http://javaj2eeplanet.blogspot.com/2008/11/stringbuilder-vs-stringbuffer.html"&gt;"StringBuilder vs. StringBuffer"&lt;/a&gt; on the Java J2ee Planet blog.  Real quickly: both StringBuilder and StringBuffer are mutable String classes; StringBuffer's mutators are synchronized for multiple threads while StringBuilder's are not.&lt;/p&gt;&lt;h4&gt;Piquing Claim&lt;/h4&gt;&lt;p&gt;The article makes one claim which piqued my interest.  Given this loop:&lt;/p&gt;&lt;pre&gt;
String result = s;
for (int i=1; i&amp;lt;times; i++) {
  result = result + s;
}
&lt;/pre&gt;&lt;p&gt;The article makes this claim:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;If called to duplicate a string 100 times, it would build 99 new String objects, 98 of which it would immediately throw away! Creating new objects is not efficient. A better solution is to use StringBuffer.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I don't dispute the math; I dispute this: "Creating new objects is not efficient."  Years ago some researchers took a look at the objects created in typical programs, and they determined that a &lt;em&gt;large&lt;/em&gt; majority of objects had &lt;em&gt;very&lt;/em&gt; short lifetimes.  This is why &lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Generational_GC_.28aka_Ephemeral_GC.29"&gt;generational garbage collection&lt;/a&gt; is so effective (and hence &lt;a href="http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html"&gt;widely used&lt;/a&gt;).&lt;/p&gt;&lt;h4&gt;Performance Experiment&lt;/h4&gt;&lt;p&gt;I implemented the code from the article to test out the claim.  It's &lt;a href="http://gist.github.com/484977"&gt;available as gist&lt;/a&gt;, and I encourage you to give it a quick scan at least.  Basically it takes the loop above, a &lt;strong&gt;dupl&lt;/strong&gt;ication algorithm, and implements it six times: duplString(), duplStringConcat(), duplStringBuilder(), duplStringBuilderAllocated(), duplStringBuffer(), duplStringBufferAllocated().  The names of the methods indicate what types of object were used in the duplication.  duplStringConcat() uses String#concat(String) to duplicate the string.  The Allocated versions use a constructor that pre-allocated the space for the final string (e.g., &lt;code&gt;new StringBuilder(s.length * times)&lt;/code&gt;).&lt;/p&gt;&lt;p&gt;On my MacBook (OS X 10.5, 2 GHz Intel Core 2 Duo, 4 GB 667 MHz DDR2 SDRAM), I got these &lt;em&gt;very&lt;/em&gt; unscientific results for 1000 duplicates:&lt;/p&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;190 ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;String#concat(String)&lt;/td&gt;&lt;td&gt;77 ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;StringBuilder&lt;/td&gt;&lt;td&gt;26 ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;StringBuffer&lt;/td&gt;&lt;td&gt;31 ms&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&gt;Curious!  First, pre-allocating space in the result didn't matter significantly, shaving only a couple seconds off the time.  Second, the synchronization of StringBuffer doesn't add &lt;em&gt;that&lt;/em&gt; much overhead.  Sure, it's 5 ms difference in my tests, but these are hardly scientific.  Before we run more tests to decide this issue, I'd ask you why you need a StringBuffer shared between concurrent threads&amp;mdash;but that's a whole different can of beans to argue about.&lt;/p&gt;&lt;p&gt;By far the most curious thing is that the String version is &lt;em&gt;significantly&lt;/em&gt; worse!  This is why we run experiments and not rely solely on analytical arguments (based on what we think the API and system docs say).  In my defense, the String version shouldn't be &lt;em&gt;that&lt;/em&gt; bad.  The best-case scenario would be a compiler that recognizes that the intermediate results never leave the loop (let alone the function), so it gets compiled into a StringBuilder version.  If nothing else, the intermediate Strings could be allocated on the stack, never taxing the garbage collector.&lt;/p&gt;&lt;h4&gt;Lessons Learned from Source Code&lt;/h4&gt;&lt;p&gt;I poked around the source code and discovered a few things.  First, the JavaDoc for String indicates that concatenation with &lt;code&gt;+&lt;/code&gt; "is implemented through the &lt;code&gt;StringBuilder&lt;/code&gt;(or &lt;code&gt;StringBuffer&lt;/code&gt;) class and its &lt;code&gt;append&lt;/code&gt; method."  So for every executed &lt;code&gt;+&lt;/code&gt; there are StringBuilders created, append()s applied, and conversions to String.  Yikes!&lt;/p&gt;&lt;p&gt;Second, String#concat(String) uses the low-level methods of String (which use System.arrayCopy()) to create the new String.  I figured this would get me closer to StringBuilder performance, but it only cuts the time in half.&lt;/p&gt;&lt;p&gt;Third, StringBuilder uses its own char[] to store the characters.  I wonder if arrays are not quite as heavy as other objects in Java?  Probably not, but it's something to consider.  StringBuilder can and does use System.arrayCopy() as often as possible, and this certainly makes a difference.&lt;/p&gt;&lt;p&gt;Finally and I suspect most importantly, StringBuilder uses an optimal algorithm for allocating incremental storage.  Whether using &lt;code&gt;+&lt;/code&gt; or concat(), String will always allocate just enough space for the new string.  So in the example above with 100 duplications, there are at least 99 array allocations, each one s.length() longer than the previous.  StringBuilder, on the other hand, uses a char[] larger than the official length of the "string" it stores.  When the char[] fills up, a new array &lt;em&gt;twice as big&lt;/em&gt; is allocated.  This means that the number of allocations is proportional to the &lt;em&gt;log (base 2)&lt;/em&gt; of the final length.  Instead of 99 char[] allocations, there's fewer than 7 allocations!&lt;/p&gt;&lt;h4&gt;What to Use&lt;/h4&gt;&lt;p&gt;Normally, my advice is to avoid premature optimizations.  But it seems to me that if you're building up a lot of Strings, using StringBuilders is good practice.  This begs the question: when you are you building up a &lt;em&gt;lot&lt;/em&gt; of Strings?  As always, profiling your app should tell you what to concentrate on.&lt;/p&gt;&lt;p&gt;On the other hand, programming to the StringBuilder interface is still pretty natural, especially if you actually program to the &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Appendable.html"&gt;Appendable&lt;/a&gt; interface.  I am a strong proponent of programming to interfaces, and this is a good motivating example.  If you pass around a StringBuilder throughout your code, you can easily retype it as an Appendable without losing anything.  You still get all of the efficiency benefits of StringBuilder, plus you can now use all the same code with a wide range of Writers (to screens, files, pipes, and streams) &lt;em&gt;without changing a thing&lt;/em&gt; and &lt;em&gt;still reap the efficiency benefits (for free)&lt;/em&gt; provided by the implementing class.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3884195844662217334?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3884195844662217334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3884195844662217334' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3884195844662217334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3884195844662217334'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/07/string-stringbuilder-stringbuilder-and.html' title='String, StringBuilder, StringBuilder, and Performance'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3537153985218274265</id><published>2010-07-11T18:34:00.001-04:00</published><updated>2010-07-11T18:34:46.540-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><title type='text'>Updated MongoDB cleaning</title><content type='html'>&lt;p&gt;I just posted a better version of my code to &lt;a href="http://jdfrens.blogspot.com/2010/06/cleaning-up-mongodb-database-after.html"&gt;clean up a MongoDB database after each RSpec and Cucumber test&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;MongoDB was complaining during my Cucumber tests that I was trying to remove a system collection.  It seems to be just a complaint in the log file, so I don't thin the change was critical, but I prefer a clean log file.&lt;/p&gt;&lt;p&gt;MongoDB &lt;em&gt;wasn't&lt;/em&gt; complaining about the same thing with my RSpec tests.  Turns out that the cleanup wasn't running because of the &lt;code&gt;:type =&amp;gt; :model&lt;/code&gt; filter on the &lt;code&gt;config.after(:each)&lt;/code&gt; call.  I dropped the filter, and the cleanup now runs after each test.  It's not optimal, but that's not particularly a problem right now.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3537153985218274265?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3537153985218274265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3537153985218274265' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3537153985218274265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3537153985218274265'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/07/updated-mongodb-cleaning.html' title='Updated MongoDB cleaning'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8839811816096940448</id><published>2010-06-30T18:34:00.002-04:00</published><updated>2010-07-11T18:27:19.382-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='mongodb'/><title type='text'>Cleaning up a MongoDB Database after RSpec and Cucumber</title><content type='html'>&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; added conditional to &lt;em&gt;not&lt;/em&gt; delete system collections.  MongoDB only complained about this, so it isn't disastrous without it.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;UPDATE #2:&lt;/strong&gt; dropped &lt;code&gt;:type =&amp;gt; :model&lt;/code&gt; from the RSpec settings.&lt;/p&gt;&lt;p&gt;Last week, I posted &lt;a href="http://jdfrens.blogspot.com/2010/06/my-rails-3-app-with-jquery-mongomapper.html"&gt;my configuration for a Rails 3 app using MongoDB, RSpec, and Cucumber&lt;/a&gt;.  (I'm also using jQuery, Ruby 1.9.2, and now &lt;a href="http://haml-lang.com/"&gt;HAML&lt;/a&gt;, but they don't matter for today's blog post.)&lt;/p&gt;&lt;p&gt;The app is for keeping track of the books that I own.  When chasing down a bug, I poked around my testing database, and discovered it had a &lt;em&gt;lot&lt;/em&gt; of entries for the book &lt;a href="http://en.wikipedia.org/wiki/Dune_(novel)"&gt;&lt;i&gt;Dune&lt;/i&gt;&lt;/a&gt; (my primary testing example).&lt;/p&gt;&lt;p&gt;These multiple entries were not related to the issue I was having, but it will be a problem in the future.  I figured I should solve it now.  My Google searches didn't reveal any direct solutions, but I was able to piece something together.&lt;/p&gt;&lt;p&gt;My solution is to remove all collections from the database after each test.  I have efficiency warnings going off in my head, but I have some time before it's actually a problem (if it ever is).&lt;/p&gt;&lt;h3&gt;Cleaning a MongoDB Database for RSpec&lt;/h3&gt;&lt;p&gt;In &lt;code&gt;spec/spec_helper.rb&lt;/code&gt; within the &lt;code&gt;Rspec.configure&lt;/code&gt; block:&lt;/p&gt;&lt;pre&gt;
config.after(:each) do
  MongoMapper.database.collections.each do |collection|
    unless collection.name.match(/^system\./)
      collection.remove
    end
  end
end
&lt;/pre&gt;&lt;p&gt;&lt;strike&gt;The &lt;code&gt;:type =&gt; :model&lt;/code&gt; restriction runs the cleanup only after model tests, not controller or view tests.&lt;/strike&gt;&lt;/p&gt;&lt;h3&gt;Cleaning a MongoDB Database for Cucumber&lt;/h3&gt;&lt;p&gt;In a new file &lt;code&gt;features/support/mongodb_clean.rb&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;
After do |scenario|
  MongoMapper.database.collections.each do |collection|
    unless collection.name.match(/^system\./)
      collection.remove
    end
  end
end
&lt;/pre&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8839811816096940448?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8839811816096940448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8839811816096940448' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8839811816096940448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8839811816096940448'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/06/cleaning-up-mongodb-database-after.html' title='Cleaning up a MongoDB Database after RSpec and Cucumber'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3530773765031146919</id><published>2010-06-25T17:47:00.001-04:00</published><updated>2010-06-25T17:47:56.080-04:00</updated><title type='text'>Legos for Adults</title><content type='html'>&lt;p&gt;I've got another TED talk to share: &lt;a href="http://www.ted.com/talks/hillel_cooperman_legos_for_grownups.html"&gt;"Legos for grownups"&lt;/a&gt; by Hillel Cooperman.  It's a rather short talk...&lt;/p&gt;&lt;!--copy and paste--&gt;&lt;object width="446" height="326"&gt;&lt;param name="movie" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;param name="bgColor" value="#ffffff"&gt;&lt;/param&gt;&lt;param name="flashvars" value="vu=http://video.ted.com/talks/dynamic/HillelCooperman_2010U-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/HillelCooperman-2010U.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=894&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=hillel_cooperman_legos_for_grownups;year=2010;theme=architectural_inspiration;theme=what_makes_us_happy;theme=the_creative_spark;event=TED2010;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" /&gt;&lt;embed src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" pluginspace="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" bgColor="#ffffff" width="446" height="326" allowFullScreen="true" allowScriptAccess="always" flashvars="vu=http://video.ted.com/talks/dynamic/HillelCooperman_2010U-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/HillelCooperman-2010U.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=894&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=hillel_cooperman_legos_for_grownups;year=2010;theme=architectural_inspiration;theme=what_makes_us_happy;theme=the_creative_spark;event=TED2010;"&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3530773765031146919?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3530773765031146919/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3530773765031146919' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3530773765031146919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3530773765031146919'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/06/legos-for-adults.html' title='Legos for Adults'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4790658713376519918</id><published>2010-06-22T18:00:00.001-04:00</published><updated>2010-06-22T18:00:05.788-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='howto'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='mongodb'/><title type='text'>My Rails 3 App with jQuery, MongoMapper, RSpec, Cucumber, and Ruby 1.9.2</title><content type='html'>&lt;p&gt;I've been interested in starting a new Ruby on Rails project for keeping track of the movies, books, and video games that I've watched, read, played, and own. I love new shiny things like Ruby 1.9 and &lt;a href="http://weblog.rubyonrails.org/2010/6/8/rails-3-0-beta-4-now-rc-in-days"&gt;Rails 3&lt;/a&gt;; I already use &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; and &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt;; I've fallen in like with &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;; and I'm &lt;em&gt;very&lt;/em&gt; curious about &lt;a href="http://www.mongodb.org/"&gt;MongoDB&lt;/a&gt; and &lt;a href="http://mongomapper.com/"&gt;MongoMapper&lt;/a&gt;.



&lt;h3&gt;My Sources&lt;/h3&gt;&lt;p&gt;I hardly had to do any real work to get this working.  These sources told me what to do:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://lindsaar.net/2010/5/9/Getting-Rails-3-Edge-with-jQuery-RSpec-and-Cucumber-using-RVM"&gt;"Getting Rails 3 Edge with jQuery, RSpec and Cucumber using RVM"&lt;/a&gt; from Mikel Lindsaar&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.mongodb.org/display/DOCS/Rails+3+-+Getting+Started"&gt;"Rails 3 - Getting Started"&lt;/a&gt; from the MongoDB documentation&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Mostly, this is a rehash of Lindsaar's HOWTO with a MongoMapper twist.  I've written my HOWTO as a blunt and raw "these are the commands I used" with an explanation afterwards.  I'm happy to elaborate on anything if I don't explain it in enough detail.&lt;/p&gt;&lt;h3&gt;Creating the App&lt;/h3&gt;&lt;pre&gt;
rvm use ruby-1.9.2
rvm gemset create Reviews
rvm gemset use Reviews
gem install rails --pre
rails new Reviews -OTJ
cd Reviews
echo "rvm ruby-1.9.2@Reviews" &gt; .rvmrc
&lt;/pre&gt;&lt;p&gt;The first three instructions use &lt;a href="http://rvm.beginrescueend.com/"&gt;rvm&lt;/a&gt; to activate Ruby 1.9.2 and to create (and use) a new gemset for this app.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;gem&lt;/code&gt; command will install the latest version of Rails 3.  You don't need to install anything else yet.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;rails&lt;/code&gt; command creates a new app without an ORM (&lt;code&gt;-O&lt;/code&gt;), without Test::Unit (&lt;code&gt;-T&lt;/code&gt;), and without Prototype (&lt;ocde&gt;-J&lt;/code&gt;).&lt;/p&gt;&lt;p&gt;The &lt;code&gt;echo&lt;/code&gt; command tells &lt;code&gt;rvm&lt;/code&gt; which version of Ruby to use with what gemset.  (I'm not entire sure if this is working well.)&lt;/p&gt;&lt;h3&gt;jQuery&lt;/h3&gt;&lt;pre&gt;
mkdir public/javascripts/jquery
curl http://code.jquery.com/jquery-1.4.2.min.js &gt; public/javascripts/jquery/
curl http://github.com/rails/jquery-ujs/raw/master/src/rails.js &gt; public/javascripts/
&lt;/pre&gt;&lt;p&gt;This drops the jQuery library in its own subfolder.  Feel free to drop jQuery plugins there.  The &lt;code&gt;rails.js&lt;/code&gt; is the wrapper around jQuery for Rails.&lt;/p&gt;&lt;p&gt;In head of &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;
  &amp;lt;%= javascript_include_tag 'jquery/jquery-1.4.2.min' %&amp;gt;
  &amp;lt;%= javascript_include_tag :all, :cache =&gt; true %&amp;gt;
&lt;/pre&gt;&lt;p&gt;Lindsaar puts these at the end of the body.  I haven't done much with jQuery, so there may be good reasons for that.&lt;/p&gt;&lt;h3&gt;Gems&lt;/h3&gt;&lt;p&gt;This is my &lt;code&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;
source 'http://rubygems.org'

gem 'rails', '3.0.0.beta4'
gem 'rails3-generators'

gem "bson_ext"
gem "mongo_mapper"

group :test, :spec, :cucumber do
  gem "rspec"
  gem "rspec-rails",      "&gt;= 2.0.0.beta"
  gem "nokogiri"
  gem "capybara"
  gem "cucumber"
  gem "database_cleaner"
  gem "cucumber-rails"
end
&lt;/pre&gt;&lt;p&gt;Then, &lt;code&gt;bundle install&lt;/code&gt; to install the gems.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;rails3-generators&lt;/code&gt; provides some useful generators.&lt;/li&gt;&lt;li&gt;&lt;code&gt;bson_ext&lt;/code&gt; is a optional binary driver for handling BSON data for the &lt;code&gt;mongo&lt;/code&gt; driver (which is a dependency of &lt;code&gt;mongo_mapper&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;I had a problem with &lt;code&gt;webrat&lt;/code&gt; and &lt;code&gt;cucumber&lt;/code&gt; and Rails 3 (and apparently others have, too), so I used &lt;code&gt;capybara&lt;/code&gt;.  (This may make &lt;code&gt;nokogiri&lt;/code&gt; unnecessary.)&lt;/li&gt;&lt;li&gt;I assume the other gems are obvious; if not, let me know.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In &lt;code&gt;config/application.rb&lt;/code&gt;,&lt;/p&gt;&lt;pre&gt;
config.generators do |g|
  g.orm             :mongo_mapper
  g.template_engine :erb
  g.test_framework  :rspec
end
&lt;/pre&gt;&lt;h3&gt;Mongo&lt;/h3&gt;&lt;p&gt;A new file, &lt;code&gt;config/initializers/mongo.rb&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;
MongoMapper.connection = Mongo::Connection.new('localhost', 27017)
MongoMapper.database = "#Reviews-#{Rails.env}"

if defined?(PhusionPassenger)
   PhusionPassenger.on_event(:starting_worker_process) do |forked|
     MongoMapper.connection.connect_to_master if forked
   end
end
&lt;/pre&gt;&lt;p&gt;This was stolen completely from the MongoDB documentation except for the database name.  Feel free to use your own database name!&lt;/p&gt;&lt;p&gt;A second file, &lt;code&gt;lib/tasks/mongo.rake&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;
namespace :db do
  namespace :test do
    task :prepare do
      # Stub out for MongoDB
    end
  end
end
&lt;/pre&gt;&lt;h3&gt;Generate Testing Frameworks&lt;/h3&gt;&lt;pre&gt;
rails generate rspec:install
rails generate cucumber:install --capybara --rspec --skip-database
&lt;/pre&gt;&lt;h3&gt;Ready to Go!&lt;/h3&gt;&lt;p&gt;The app I have now seems to be ready for development.  If I run into any problems, I'll post an update.&lt;/p&gt;

&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4790658713376519918?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4790658713376519918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4790658713376519918' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4790658713376519918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4790658713376519918'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/06/my-rails-3-app-with-jquery-mongomapper.html' title='My Rails 3 App with jQuery, MongoMapper, RSpec, Cucumber, and Ruby 1.9.2'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4800970500785544906</id><published>2010-06-21T14:29:00.001-04:00</published><updated>2010-06-21T14:29:26.696-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='system administration'/><title type='text'>Happy with My Backup Service</title><content type='html'>&lt;p&gt;Way back in March, I &lt;a href="http://twitter.com/jdfrens/status/11336092555"&gt;tweeted my thoughts about the backup service I was using.&lt;/a&gt;  Since I've found a good replacement, I figured I should report on it.&lt;/p&gt;&lt;h3&gt;Mozy, You're Okay&lt;/h3&gt;&lt;p&gt;I originally picked Mozy for my backups because I had heard good things about them, and a few months after trying them out, I also picked them for my parents' computer.  My parents have actually had pretty good service from them, but then they have only a couple of gigabytes to back up on a WinXP machine.&lt;/p&gt;&lt;p&gt;I have a MacBook with over 140 GB of data to backup.&lt;/p&gt;&lt;p&gt;Mozy's support for Macs always seemed to a second thought.  When a friend and I tested them out one afternoon several years ago, restoring a file on a Windows machine was &lt;em&gt;really&lt;/em&gt; easy, but on a Mac it was &lt;em&gt;really&lt;/em&gt; obnoxious.  Occasionally, I'd have problems which would require opening the Console app to get at an error message, and once I even had to reinstall Mozy and wipe my configuration from my Library folder.&lt;/p&gt;&lt;p&gt;As for my data needs, the amount of data should really only be a problem with the initial backup.  Incremental backups after that shouldn't amount to much.&lt;/p&gt;&lt;h3&gt;Mozy, You Suck&lt;/h3&gt;&lt;p&gt;A few weeks before my tweet, Mozy updated itself on my MacBook.  Once the update was finished, it decided that &lt;em&gt;all 140 GB of data that it had been backed up just fine had to be backed up &lt;strong&gt;from scratch&lt;/strong&gt; from my computer to their servers&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Now, I can imagine scenarios where this might be necessary.  A secret encryption key lives on my computer, and only that key can be used to encrypt and decrypt the files off the server.  And maybe they upgraded their servers with a new encryption algorithm, so to keep the secret key on my computer and not in their grubby hands the backup had to be redone from my computer.&lt;/p&gt;&lt;p&gt;But couldn't you have told me this when I did the upgrade?  Better yet, you couldn't preserve some backwards compatibility?&lt;/p&gt;&lt;p&gt;On the day of my tweet, Mozy updated itself again.  &lt;em&gt;And it decided to back everything up again from scratch.&lt;/em&gt;  We can speculate why it was necessary this second time, but none of the scenarios make me happy&amp;mdash;either the people at Mozy are lazy or stupid.&lt;/p&gt;&lt;p&gt;However, if starting over from scratch was the only problem I had, I probably would have stayed with Mozy, and my tweet would have been a mild profanity-free complaint.&lt;/p&gt;&lt;h3&gt;Mozy, You &lt;em&gt;Really&lt;/em&gt; Suck&lt;/h3&gt;&lt;p&gt;After the first upgrade, I had the Mozy status screen open, and I noticed it wanted to back everything up again.  It didn't make me happy, but I figured I'd let it run overnight, and I'd decide how to handle this in the morning.&lt;/p&gt;&lt;p&gt;The next morning, my internal hard drive was full, RAM was maxed out, and my MacBook was in a bad way.  I shut down programs as best I could and rebooted.  It came back fine until Mozy started another backup process.  Then the RAM filled up, the hard drive got full, and my MacBook was again in a bad way.&lt;/p&gt;&lt;p&gt;This time I only told Mozy to stop its back up process, and I got my RAM and hard drive back.  So I tried an experiment.  Instead of backing up all 140 GB of my data, I told it to back up just one small folder.  No problem.  So I added a couple more folders.  No problem.  I tried a much larger folder.  Problem!!!!  Okay, fine, I'll add just a few folders at a time.  I followed this procedure for several &lt;em&gt;weeks&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Meanwhile, figuring this was a serious flaw in their backup algorithm, I shot an email to Mozy support.  I mean, &lt;em&gt;I'm&lt;/em&gt; doing a &lt;em&gt;computation&lt;/em&gt; to make the backup &lt;em&gt;algorithm&lt;/em&gt; work better.  It's not a difficult computation either (i.e., "pick a few small folders, back them up"), so it &lt;em&gt;has&lt;/em&gt; to be their problem.  &lt;strong&gt;Nope!&lt;/strong&gt;  The response I got back from Mozy's tech support was that's the way things worked, and I'd have to add folders myself from time to time to get everything backed up again.&lt;/p&gt;&lt;p&gt;&lt;em&gt;And then Mozy updates again, and I have to start this whole process over again.&lt;/em&gt;  This is where profanity laced tweets come from.&lt;/p&gt;&lt;h3&gt;Crashplan, You Seem to Be Awesome&lt;/h3&gt;&lt;p&gt;After my tweet, I started looking for other online backup services.  I had heard good things about &lt;a href="http://www.carbonite.com/"&gt;Carbonite&lt;/a&gt;, but I never got around to trying them out.&lt;/p&gt;&lt;p&gt;A couple people recommended &lt;a href="http://www.crashplan.com/"&gt;CrashPlan&lt;/a&gt; to me.  So far, it's been working very well.&lt;/p&gt;&lt;p&gt;Obviously, it had to back up everything from scratch, and this took a couple of weeks, but it went very smoothly.  I specified &lt;em&gt;all&lt;/em&gt; of the folders I wanted backed up, and it backed them up without overwhelming my computer or network.&lt;/p&gt;&lt;p&gt;I've restored files from the online backup, and this goes smoothly and fairly quickly.  I believe I've gone through at least one software update without problems.&lt;/p&gt;&lt;p&gt;CrashPlan is available on Windows and Linux(!) platforms.  Plus, you can backup to other computers, to your own or even to a friend's.&lt;/p&gt;&lt;p&gt;So after several months of using CrashPlan, I'm willing to say that &lt;a href="http://www.crashplan.com/"&gt;CrashPlan is awesome&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4800970500785544906?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4800970500785544906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4800970500785544906' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4800970500785544906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4800970500785544906'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/06/happy-with-my-backup-service.html' title='Happy with My Backup Service'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5441915918976917089</id><published>2010-06-03T21:09:00.002-04:00</published><updated>2010-06-07T15:30:00.215-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='iterative programming'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Functional Programming for Dummies</title><content type='html'>&lt;p&gt;Here's how you write factorial in Haskell:&lt;/p&gt;&lt;pre&gt;factorial n = product [1..n]&lt;/pre&gt;&lt;p&gt;Boy, that &lt;em&gt;is&lt;/em&gt; hard to read.&lt;/p&gt;&lt;h3&gt;Give Me Some Context, Please!&lt;/h3&gt;&lt;p&gt;I was going to let this pass: &lt;a href="http://nerds-central.blogspot.com/2009/03/why-functional-programming-will-not.html"&gt;"Why Functional Programming Will Not Take Over The World - A Square Peg In A Round Hole"&lt;/a&gt; by Alex Turner.  Turner is the genius who determined that &lt;a href="http://nerds-central.blogspot.com/2010/05/knife-is-out-for-ruby.html"&gt;Ruby was dead because it dropped 0.6% in popularity over the last year&lt;/a&gt;.  This dropped it out of the top ten, so therefore the "knife was out" and "Ruby is doomed".&lt;/p&gt;&lt;p&gt;Now he's complaining about functional programming.  His stated complaint is that people think iteratively, not functionally.  So functional languages won't take over the world.  (Who knew that was their goal?  Did I miss a memo?)  His &lt;em&gt;actual&lt;/em&gt; complaint is that &lt;em&gt;he&lt;/em&gt; doesn't think that he thinks functionally or recursively, so therefore everyone must think iteratively.&lt;/p&gt;&lt;p&gt;Now, granted, I'm horribly biased here.  &lt;a href="http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR568"&gt;My dissertation&lt;/a&gt; dealt with FP and high-performance computing: using structural and functional decomposition to get the most out of the memory hierarchy (caches, RAMs, virtual memories) and out of multiple processors.  These days, I write Java and Ruby code, and most (if not all) of my OO programming is functional: I never write setter/mutator methods, and I often encode algorithms in their own objects (essentially closures).&lt;/p&gt;&lt;p&gt;In short, I like functional programming.&lt;/p&gt;&lt;h3&gt;Turner Is the Round Hole&lt;/h3&gt;&lt;p&gt;Tuner's argument comes down to three snippets of code.  First, the oh so unreadable ML version of factorial:&lt;/p&gt;&lt;pre&gt;
fun fac 0 = 1
  | fac n = n * fac (n-1)
&lt;/pre&gt;&lt;p&gt;It's identical to the definition you'd find in any mathematics textbook.  I think it's immensely readable.  The Haskell version at the top of this article is even more readable.&lt;/p&gt;&lt;p&gt;Turner's &lt;em&gt;favorable&lt;/em&gt; alternatives micromanage the computation.  First, he writes it in VSPL:&lt;/p&gt;&lt;pre&gt;
1 !r 
2,?n,{ ,?r:Prod !r }:Repeat
&lt;/pre&gt;&lt;p&gt;WTF?  Really?  &lt;em&gt;That's&lt;/em&gt; better than the ML or Haskell versions?  Granted, I'm reacting mostly to the syntax here, but if you're going to pull out an example of how iteration is better, you go for this?  A C++ version would be better.  Why not Pascal?  When I read this code, I actually thought Turner was writing satire because I can't imagine how this is better than the ML version, and I even now I can't shake this suspicion...&lt;/p&gt;&lt;p&gt;Turner does marginally better with a COBOL version:&lt;/p&gt;&lt;pre&gt;
move 1 to r
perform varying i from 2 by 1 until i&gt;n
    multiply r by i giving r
end-perform
&lt;/pre&gt;&lt;p&gt;COBOL tends to read like really awkward, pedantic English, so this is at least readable.  (I know that the result ends up in &lt;code&gt;r&lt;/code&gt;.)  But the COBOL syntax still gets in the way of the readability.&lt;/p&gt;&lt;p&gt;But let's push the syntax to the side.  Turner summarizes his COBOL version like this:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The above COBOL is quite close to how one might think of a factorial calculation and so needs almost no mental translation.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;That's how one might think about it if they're worried about machine registers or memory locations.  Notice how the iterative version need an explicit accumulator, namely &lt;code&gt;r&lt;/code&gt;?  The functional versions don't.  Now compare this to a natural, English description of factorial: "n! is the product of the numbers 1 through n".  Where's the accumulator?  Where's the iteration variable &lt;code&gt;i&lt;/code&gt;?  Which code matches that description better?  (Answer: Haskell!)&lt;/p&gt;&lt;p&gt;Reading between the lines, I claim that &lt;em&gt;Turner&lt;/em&gt; is the one with the misconception.  I've encountered too many colleagues who've been warped by FORTRAN (or C or Pascal) and the iterative mindset.  At a certain point (the age of the person, the depth of the mindset), they can't do functional programming, especially recursion.  These people start to believe that iterative thought is the natural way we think of computations.&lt;/p&gt;&lt;h3&gt;My Take&lt;/h3&gt;&lt;p&gt;First, what's with the melodrama?  FP won't "take over the world"?  Well, here's a news flash: iterative and OO won't take it over either.  Neither will &lt;a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming"&gt;AOP&lt;/a&gt;, logic programming, or &lt;a href="http://en.wikipedia.org/wiki/Esoteric_programming_language"&gt;esoteric programming&lt;/a&gt;.  Each of these paradigms have their own niches, and they'll flourish just fine there (&lt;em&gt;especially&lt;/em&gt; esoteric programming).&lt;/p&gt;&lt;p&gt;Second, I hate factorial (or Fibonacci) as the go-to FP example.  And in this case it works completely counter to Turner's argument.  The ML and Haskell versions are perfectly readable, and much better than his iterative alternatives.  If you're going to make any arguments for or against FP, use some code that proves to me that you've actually programmed in the language yourself, not copied code out of another blog post.&lt;/p&gt;&lt;p&gt;Third, there's a constructive case to be made for FP.  Ruby and Python already support a functional paradigm since closures are first-class citizens.  Other languages (Java, C++, C#, PHP) are looking to add them.  These features are not needed, but &lt;em&gt;because programmers are thinking functionally&lt;/em&gt;, they want FP tools.&lt;/p&gt;&lt;p&gt;Finally, where's the cognitive research on this topic?  Turner is ultimately making a claim that iterative is better, although he starts by posing that FP cannot be mapped onto our brains.  These are questions for psychologists and cognitive scientists doing real studies, not some guys saying, "I don't get it, so no one else can."&lt;/p&gt;&lt;h3&gt;Not Interested&lt;/h3&gt;&lt;p&gt;I'm not interested in arguments against FP based on syntax (e.g., whitespace in Haskell, parentheses in LISP/Scheme) or based on orthogonal features of a language (e.g., Haskell's type system).  You can dislike a language because of these things, but those are separate issues.  They have nothing to do with the value of functional programming.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I fixed &lt;em&gt;the most important link I had in my entire article&lt;/em&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5441915918976917089?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5441915918976917089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5441915918976917089' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5441915918976917089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5441915918976917089'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/06/functional-programming-for-dummies.html' title='Functional Programming for Dummies'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3947106914927573778</id><published>2010-06-01T13:42:00.002-04:00</published><updated>2010-06-01T13:46:38.629-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='user interface'/><category scheme='http://www.blogger.com/atom/ns#' term='presentation'/><title type='text'>The Future of UI</title><content type='html'>&lt;p&gt;Another TED talk...&lt;/p&gt;&lt;!--copy and paste--&gt;&lt;object width="446" height="326"&gt;&lt;param name="movie" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;param name="bgColor" value="#ffffff"&gt;&lt;/param&gt;&lt;param name="flashvars" value="vu=http://video.ted.com/talks/dynamic/JohnUnderkoffler_2010-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/TedTalks-1609.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=872&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=john_underkoffler_drive_3d_data_with_a_gesture;year=2010;theme=new_on_ted_com;theme=tales_of_invention;theme=technology_history_and_destiny;theme=presentation_innovation;theme=a_taste_of_ted2010;theme=what_s_next_in_tech;event=TED2010;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" /&gt;&lt;embed src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" pluginspace="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" bgColor="#ffffff" width="446" height="326" allowFullScreen="true" allowScriptAccess="always" flashvars="vu=http://video.ted.com/talks/dynamic/JohnUnderkoffler_2010-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/TedTalks-1609.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=872&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=john_underkoffler_drive_3d_data_with_a_gesture;year=2010;theme=new_on_ted_com;theme=tales_of_invention;theme=technology_history_and_destiny;theme=presentation_innovation;theme=a_taste_of_ted2010;theme=what_s_next_in_tech;event=TED2010;"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;p&gt;John Underkoffler got to show off his UI research in &lt;a href="http://www.imdb.com/title/tt0181689/"&gt;&lt;i&gt;Minority Report&lt;/i&gt;&lt;/a&gt;.  I don't know how much was mocked up in that movie (which is eight years old now), but Underkoffler takes on the ultimate live demo in this talk.  He shows off what his system can do now, and it's quite impressive.&lt;/p&gt;&lt;p&gt;One thing that concerns me regarding these newfangled interfaces is that hand gestures get you only so far.  Way back in 1996, Don Gentner and Jakob Nielsen wrote an article &lt;a href="http://portal.acm.org/citation.cfm?doid=232014.232032"&gt;"The Anti-Mac Interface"&lt;/a&gt; for the &lt;i&gt;Communications of the ACM&lt;/i&gt;.  The most important observation for me from this article was that the mouse and GUI reduced our communication to the grunts and crude gestures of cavemen.&lt;/p&gt;&lt;p&gt;Underkoffler's system &lt;em&gt;is&lt;/em&gt; better: hand gestures are more expressive than a mouse; he's got an extra spacial dimension to play in; the network awareness is &lt;em&gt;really&lt;/em&gt; cool.  But at some point you have to describe complicated business rules to the system, and these require at least &lt;em&gt;some&lt;/em&gt; words.  I'm curious how that input works and how well it works.  Underkoffler mentions that the system is in use now on real problems with real users, so the ability must be there, I'm just curious how well it works.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3947106914927573778?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3947106914927573778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3947106914927573778' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3947106914927573778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3947106914927573778'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/06/future-of-ui.html' title='The Future of UI'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2958962572605728569</id><published>2010-05-25T15:29:00.002-04:00</published><updated>2010-05-25T16:07:16.560-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='copyright'/><category scheme='http://www.blogger.com/atom/ns#' term='open source software'/><title type='text'>Can't Copyright Fashion</title><content type='html'>&lt;p&gt;I've got another video to share today.  Perhaps I found this really interesting since I've been avidly watching the last few seasons on Project Runway, but this TED talk from Johanna Blakely on copyright and fashion design is really interesting:&lt;/p&gt;

&lt;!--copy and paste--&gt;&lt;object width="334" height="326"&gt;&lt;param name="movie" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;param name="bgColor" value="#ffffff"&gt;&lt;/param&gt;&lt;param name="flashvars" value="vu=http://video.ted.com/talks/dynamic/JohannaBlakley_2009X-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/JohannaBlakely-2009X.embed_thumbnail.jpg&amp;vw=320&amp;vh=240&amp;ap=0&amp;ti=866&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=johanna_blakley_lessons_from_fashion_s_free_culture;year=2010;theme=unconventional_explanations;theme=design_like_you_give_a_damn;theme=art_unusual;theme=the_creative_spark;theme=new_on_ted_com;theme=not_business_as_usual;theme=tales_of_invention;event=TEDxUSC;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" /&gt;&lt;embed src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" pluginspace="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" bgColor="#ffffff" width="334" height="326" allowFullScreen="true" allowScriptAccess="always" flashvars="vu=http://video.ted.com/talks/dynamic/JohannaBlakley_2009X-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/JohannaBlakely-2009X.embed_thumbnail.jpg&amp;vw=320&amp;vh=240&amp;ap=0&amp;ti=866&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=johanna_blakley_lessons_from_fashion_s_free_culture;year=2010;theme=unconventional_explanations;theme=design_like_you_give_a_damn;theme=art_unusual;theme=the_creative_spark;theme=new_on_ted_com;theme=not_business_as_usual;theme=tales_of_invention;event=TEDxUSC;"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;My summary: fashion can't be copyrighted, but that's okay.  It encourages more and better design; it makes us a lot of money.  Blakely talks about other arts and technologies that can't be copyrighted, like car designs and food recipes.  But she gets software copyrights wrong.&lt;/p&gt;

&lt;p&gt;She mentions open source software as not having a copyright, and that's not quite correct.  It has a &lt;a href="http://en.wikipedia.org/wiki/Copyleft"&gt;copyleft&lt;/a&gt;: copy and modify my code, but preserve its pedigree.  Plus, it's voluntary.  There are plenty who copyright their software in traditional ways.&lt;/p&gt;

&lt;p&gt;This talk of copyright reminded me of a recent Internet conversation the science fiction community has had over fan fiction.  I only sampled a bit of the conversation, and mostly from &lt;a href="http://grrm.livejournal.com/152340.html"&gt;George R. R. Martin&lt;/a&gt;.  I don't have much love for fan fiction, probably because the first piece I read was a Star Trek Next Generation episode with way, &lt;em&gt;way, &lt;strong&gt;way&lt;/strong&gt;&lt;/em&gt; too much exposition in its opening scene.  It also doesn't help when the quality of official spin-off books aren't well written either.  (I'm looking at you, Timothy Zahn and your Thrawn trilogy.  Lu-uke, indeed.)  As Martin points out, there's something very damaging to the original property when a follow up isn't as good.&lt;/p&gt;

&lt;p&gt;I find it very curious how I come to very different conclusions on the copyright issue in these three domains.  Fashion seems to have done quite well without copyright protection, and the legal reasoning for no copyright (clothing is too utilitarian) seems sound to me.  So no copyright for them.  I still believe that open source is the best way to develop software, certainly for certain types of software.  But I also use and &lt;em&gt;love&lt;/em&gt; some copyrighted software: Mac OS X, Civilization IV, RubyMine, iTunes, MarsEdit, TextMate, Things&amp;mdash;just to name a few that I'm running now or would like to.  So make copyright an option for them.  George R. R. Martin and &lt;a href="http://en.wikipedia.org/wiki/Bill_Watterson"&gt;Bill Watterson&lt;/a&gt; (of &lt;a href="http://en.wikipedia.org/wiki/Calvin_and_Hobbes"&gt;Calvin &amp;amp; Hobbes&lt;/a&gt; fame) want to protect their worlds and characters, and derivatives dilute their creations.  So allow them lots of copyright.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2958962572605728569?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2958962572605728569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2958962572605728569' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2958962572605728569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2958962572605728569'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/05/can-copyright-fashion.html' title='Can&amp;#39;t Copyright Fashion'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5910686875716660377</id><published>2010-05-10T16:45:00.001-04:00</published><updated>2010-05-10T16:45:02.429-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='nosql'/><category scheme='http://www.blogger.com/atom/ns#' term='mongodb'/><category scheme='http://www.blogger.com/atom/ns#' term='presentation'/><title type='text'>MongoMapper</title><content type='html'>I watched a presentation from &lt;a href="http://railstips.org/about/"&gt;John Nunemaker&lt;/a&gt; today about his &lt;a href="http://github.com/jnunemaker/mongomapper"&gt;MongoMapper Ruby gem&lt;/a&gt;.  I've been interested in MongoDB and a Ruby ORM, and I &lt;a href="http://github.com/jdfrens/database-paradigm-shift"&gt;tried out MongoMapper in my spike&lt;/a&gt;.

John's presentation really encourages me to keep with MongoMapper.  It works very well, and the plugin architecture is really simple and powerful.

Here's the presentation:

&lt;embed src="http://blip.tv/play/AYHc4EMC" type="application/x-shockwave-flash" width="480" height="390" allowscriptaccess="always" allowfullscreen="true"&gt;&lt;/embed&gt;

And you might want these slides while watching and listening:

&lt;div style="width:425px" id="__ss_3922950"&gt;&lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/jnunemaker/mongomapper-mapping-ruby-to-and-from-mongo" title="MongoMapper - Mapping Ruby to and from Mongo"&gt;MongoMapper - Mapping Ruby to and from Mongo&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse3922950" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=mongomapper-100430155022-phpapp02&amp;stripped_title=mongomapper-mapping-ruby-to-and-from-mongo" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse3922950" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=mongomapper-100430155022-phpapp02&amp;stripped_title=mongomapper-mapping-ruby-to-and-from-mongo" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding:5px 0 12px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jnunemaker"&gt;John Nunemaker&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5910686875716660377?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5910686875716660377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5910686875716660377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5910686875716660377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5910686875716660377'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/05/mongomapper.html' title='MongoMapper'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-6050507910126053079</id><published>2010-04-27T18:33:00.001-04:00</published><updated>2010-04-27T18:33:27.316-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='programming style'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Should I Use "Should" to Describe What an RSpec Example Should Expect?</title><content type='html'>&lt;p style="clear: both"&gt;Chris O'Sullivan opined on his blog today: &lt;a href="http://www.thechrisoshow.com/2010/4/27/get-real-with-your-specs-punk" target="_blank"&gt;"Get real with your specs, punk"&lt;/a&gt;. He poses the same question I started thinking about last week: should "should" be used in an RSpec description?&lt;/p&gt;&lt;p style="clear: both"&gt;For example (mine, not his):&lt;/p&gt;&lt;pre style="clear: both"&gt;describe "/home/index.html.erb" do
  it "&amp;lt;b&gt;should render&amp;lt;/b&gt; the home page"
end
&lt;/pre&gt;&lt;p style="clear: both"&gt;versus&lt;/p&gt;&lt;pre style="clear: both"&gt;describe "/home/index.html.erb" do
  it "&amp;lt;b&gt;renders&amp;lt;/b&gt; the home page"
end
&lt;/pre&gt;&lt;p style="clear: both"&gt;I may have convinced myself to drop the "should" in the description. It's more terse and less repetitive. (And more like Clint Eastwood, as O'Sullivan points out.)&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h3&gt;Should Phrasing in JUnit Assertions&lt;/h3&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;  &lt;/p&gt;&lt;p style="clear: both"&gt;Several years ago while writing JUnit assertions, I discovered the very important power of the word "should". When I wrote a JUnit assertion, I would include a descriptive message. I found that when an assertion failed that descriptive message was &lt;em&gt;very&lt;/em&gt; helpful in figuring out what when wrong. I discovered, though, that if the message were positive, it was confusing.&lt;/p&gt;&lt;p style="clear: both"&gt;Stretching my example:&lt;/p&gt;&lt;pre style="clear: both"&gt;assertEquals("renders the home page", "&amp;lt;html&amp;gt;...&amp;lt;/html&amp;gt;", indexPage.render());
&lt;/pre&gt;&lt;p style="clear: both"&gt;When this fails, JUnit displays "renders the home page". I'd have to process it: "Wait?! It displays the home page? Then what's the matter? Ohhhh! It &lt;em&gt;should&lt;/em&gt; render the home page!"&lt;/p&gt;&lt;pre style="clear: both"&gt;assertEquals("should render the home page", "&amp;lt;html&amp;gt;...&amp;lt;/html&amp;gt;", indexPage.render());
&lt;/pre&gt;&lt;p style="clear: both"&gt;The message still works as a comment for the code itself (this is what I intend by this assertion) and now as an appropriate error message (this &lt;em&gt;should&lt;/em&gt; have happened, but didn't).&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h3&gt;Error Messages from RSpec&lt;/h3&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;The primary error message comes from an RSpec matcher, and its API is really good at producing excellent error messages.  And the &lt;code&gt;should&lt;/code&gt; method, which triggers the matcher, self-documents the code very nicely.  So &lt;em&gt;that's&lt;/em&gt; where the "should" phrasing belongs.&lt;/p&gt;&lt;p style="clear: both"&gt;But perhaps the description gets in the way? Fortunately, no, as a quick experiment proved to me.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h3&gt;An Experiment&lt;/h3&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;  &lt;/p&gt;&lt;p style="clear: both"&gt;My example is taken from a project I've been working on, and it was an easy way to run a experiment. I tweaked my code so that an expectation would fail.&lt;/p&gt;&lt;p style="clear: both"&gt;In RubyMine, the &lt;code&gt;should&lt;/code&gt; method produces an obvious error message in its own window, and the example's description is in a separate panel only to give context.  Perfectly fine.&lt;/p&gt;&lt;p style="clear: both"&gt;When I ran the specs on the command line, I got this output:&lt;/p&gt;&lt;pre style="clear: both"&gt;'/home/index.html.erb renders the home page' FAILED
expected following output to contain a &amp;lt;img src="/images/foobar.jpgXXXX" /&amp;gt; tag:
&lt;/pre&gt;&lt;p style="clear: both"&gt;Using the word "FAILED" so clearly in the output makes it clear that the rendering failed. The &lt;code&gt;should&lt;/code&gt; method and the matcher do their part to specify exactly what went wrong.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h3&gt;RSpec Report&lt;/h3&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;  &lt;/p&gt;&lt;p style="clear: both"&gt;Actually, an example description can be used when the example passes: an RSpec report. RSpec allows you to run all the tests and outputs the description for &lt;em&gt;all&lt;/em&gt; the examples, passing and failing. But it turns out that's okay, too:&lt;/p&gt;&lt;pre style="clear: both"&gt;/home/index.html.erb
- renders the home page
&lt;/pre&gt;&lt;p style="clear: both"&gt;It's not any better or worse with a "should" phrasing unless this report is somehow being used for the client, and the client &lt;em&gt;really&lt;/em&gt; wants "should" phrasing.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-6050507910126053079?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/6050507910126053079/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=6050507910126053079' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6050507910126053079'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6050507910126053079'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/04/should-i-use-to-describe-what-rspec.html' title='Should I Use &amp;quot;Should&amp;quot; to Describe What an RSpec Example Should Expect?'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1860344594765307678</id><published>2010-04-06T17:26:00.001-04:00</published><updated>2010-04-06T17:26:16.105-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='databases'/><category scheme='http://www.blogger.com/atom/ns#' term='nosql'/><category scheme='http://www.blogger.com/atom/ns#' term='document-databases'/><title type='text'>Presentation about MongoDB</title><content type='html'>&lt;p style="clear: both"&gt;I've been &lt;a href="http://github.com/jdfrens/database-paradigm-shift" target="_blank"&gt;playing around with MongoDB&lt;/a&gt; lately, and I watched a presentation from RubyConf 2009: &lt;a href="http://rubyconf2009.confreaks.com/19-nov-2009-16-20-getting-non-relational-with-mongodb-michael-dirolf.html" target="_blank"&gt;"Getting Non-Relational with MongoDB"&lt;/a&gt; by Michael Dirolf. It's a good talk, and if you know little or nothing about MongoDB or document databases, it's well worth a watch. If you want a quick look, check out &lt;a href="http://www.slideshare.net/mdirolf/mongodb-at-rubyconf" target="_blank"&gt;the slides for his talk&lt;/a&gt;.&lt;/p&gt;&lt;p style="clear: both"&gt;I also recommend &lt;a href="http://rubyconf2009.confreaks.com/20-nov-2009-09-30-nosql-death-to-relational-databases-ben-scofield.html" target="_blank"&gt;"NoSQL: Death to Relational Databases"&lt;/a&gt; by Ben Scofield. It's an overview of non-SQL database systems. Since he has only 45 minutes, he doesn't spend much time on any one system, but he does a good job of categorizing and analyzing them. He gives some great code snippets that highlight how each system is used for their particular strength. (That is, his example for Redis is &lt;em&gt;much&lt;/em&gt; different for Neo4J since the former is just a key-value store and the latter is a graph database.)&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1860344594765307678?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1860344594765307678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1860344594765307678' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1860344594765307678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1860344594765307678'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/04/presentation-about-mongodb.html' title='Presentation about MongoDB'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7671434761870155876</id><published>2010-03-24T18:57:00.001-04:00</published><updated>2010-03-24T18:57:41.958-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><title type='text'>Collatz Numbers (Project Euler Problem 14)</title><content type='html'>&lt;p style="clear: both"&gt;Problem 14 of &lt;a href="http://projecteuler.net/" target="_blank"&gt;Project Euler&lt;/a&gt; deals with the &lt;a href="http://en.wikipedia.org/wiki/Collatz_conjecture" target="_blank"&gt;Collatz conjecture&lt;/a&gt;. In particular, how long does it take for a particular integer to be reduced to 1? Here's my solution in Erlang:&lt;/p&gt;&lt;pre style="clear: both"&gt;collatz(1) -&amp;gt; 1;
collatz(N) -&amp;gt;
  if
    N rem 2 == 0 -&amp;gt;
      1 + collatz(N div 2);
    true -&amp;gt;
      1 + collatz(3 * N + 1)
  end.
&lt;/pre&gt;&lt;p style="clear: both"&gt;This is what I'm calling a "Collatz number". Problem 14 is to find the number less than a million which has the largest Collatz number.&lt;/p&gt;&lt;p style="clear: both"&gt;If a problem screamed "&lt;a href="http://en.wikipedia.org/wiki/Memoization" target="_blank"&gt;&lt;strong&gt;Memoization&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;!!!&lt;/strong&gt;", this is it. Except that it shouldn't. It &lt;em&gt;does&lt;/em&gt; help (which we'll get to), but it turns out to not be necessary.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h2&gt;Brute Force Solution&lt;/h2&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;To find the maximum Collatz number in Erlang, I used this function (with the one above):&lt;/p&gt;&lt;pre style="clear: both"&gt;maximum_collatz_under(N) -&amp;gt;
  {_, Index} = max(map(fun (X) -&amp;gt; {collatz(X), X} end, seq(1, N))),
  Index.
&lt;/pre&gt;&lt;p style="clear: both"&gt;&lt;code&gt;seq(1,N)&lt;/code&gt; returns a list of integers. The function I map over this list returns a tuple of both the original number and its Collatz number. I need to take the maximum over the Collatz numbers, but I need to return the original number. Erlang's tuple data-structure is really helpful here; I &lt;em&gt;love&lt;/em&gt; how tuples are ordered (as they are in Haskell).&lt;/p&gt;&lt;p style="clear: both"&gt;There are many ways in which this should be &lt;em&gt;really&lt;/em&gt; inefficient. First, the original collatz(N) function repeats a lot of computations: to compute collatz(32), it would be helpful if I already know collatz(16). And to compute collatz(5), it &lt;em&gt;also&lt;/em&gt; helps to known collatz(16). This is where memoization would help. And it does, but we'll get to that.&lt;/p&gt;&lt;p style="clear: both"&gt;There's another inefficiency in the maximum search. First, &lt;code&gt;seq()&lt;/code&gt; creates a list of all integers in the sequence. The call to &lt;code&gt;map()&lt;/code&gt; creates another list, this one of tuples of integers. Then &lt;code&gt;max()&lt;/code&gt; goes through that list. However, none of the intermediate lists are necessary. The Collatz number can be computed as part of maximum search like so (in Python):&lt;/p&gt;&lt;pre style="clear: both"&gt;def maximum_collatz_under(n):
    if n == 1:
        return 1
    maximum = 0
    maxIndex = 0
    for i in range(1, n+1):
        collatzOfI = collatz(i)
        if collatzOfI &amp;gt; maximum:
            maximum = collatzOfI
            maxIndex = i
    return maxIndex    
&lt;/pre&gt;&lt;p style="clear: both"&gt;In Haskell, this could be done with a foldl:&lt;/p&gt;&lt;pre style="clear: both"&gt;maximumCollatzUnder_with_foldl_and_maximum n = index
  where (_, index) = foldl' f (0, 0) [1..n]
        f acc i = maximum [acc, (collatz i, i)]&lt;/pre&gt;&lt;p style="clear: both"&gt;&lt;h2&gt;Actual Efficiencies&lt;/h2&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;You may be asking yourself, "Why not show off your list-avoiding Erlang solution?" My answer: "&lt;em&gt;I don't need one.&lt;/em&gt;" It's the fastest non-memoizing solution I have! It runs around 13.3 seconds. Without memoization and without the explicit lists, Haskell runs in just over 19 seconds, Python around 100 seconds. Erlang for the win!&lt;/p&gt;&lt;p style="clear: both"&gt;However, if you know my polyglot tendencies, you'll notice I haven't mentioned one language yet: Ruby. No, I'm not embarrassed by Ruby since &lt;em&gt;Ruby produced the fastest solution of all my languages&lt;/em&gt;.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h2&gt;Memoization For the Real Win&lt;/h2&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;I actually created by Ruby solution first for this problem, back when I thought I &lt;em&gt;had&lt;/em&gt; to use memoization.&lt;/p&gt;&lt;p style="clear: both"&gt;For my first attempt, I memoized everything. This failed miserably.&lt;/p&gt;&lt;p style="clear: both"&gt;When computing a Collatz sequence, the numbers can get larger than the original number (e.g., collatz(999,999) = 1 + collatz(2,999,998)). That's a lot of memory to allocate to this problem, and given the problems constraints, very little of the memoization space between collatz(1,000,000) and collatz(2,999,998) would be used.&lt;/p&gt;&lt;p style="clear: both"&gt;I also allocated the memoization space dynamically. That is, I accessed the Ruby array as if it were infinitely long. So when I accessed an array element that hadn't been created yet, the array had to grow. There are ways so that the growth is managed sensibly, so I don't think this was a huge problem, but it doesn't help when you're talking about 3,000,000 element arrays (or larger).&lt;/p&gt;&lt;p style="clear: both"&gt;So for my second attempt, I memoized only collatz(1) through collatz(999,999). I allocated just one array for those values. When computing the Collatz number of an integer larger than 999,999, I just used the standard recursion, falling back on the memoization when possible. Here's the code:&lt;/p&gt;&lt;pre style="clear: both"&gt;class Integer
  @@collatz = Array.new(10000000)

  def collatz
    if self &amp;gt;= @@collatz.length
      self.raw_collatz
    else
      @@collatz[self] ||= self.raw_collatz
    end      
  end

  def raw_collatz
    if self == 1
      return 1
    elsif self.even?
      (self / 2).collatz + 1
    else
      (3 * self + 1).collatz + 1
    end
  end
end
&lt;/pre&gt;&lt;p style="clear: both"&gt;The array never has to grow, so that overhead isn't a problem. Most computations &lt;em&gt;can&lt;/em&gt; use the memoization, so it delivers a real benefit. Raw recursion is used only for original computations and for the occasional extra-large value for n. This solution runs in around 6.7 seconds with Ruby 1.8.7; it drops to 2.7 seconds if I use the Ruby 1.9 interpreter!&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h2 style="clear: both"&gt;Declaring a Winner&lt;/h2&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;  &lt;/p&gt;&lt;p style="clear: both"&gt;The real winner here is not Ruby itself, but the memoization. I couldn't get memoization to work in Haskell. (I'm going to have to think about it some more.) I'm really not sure how to do memoization in Erlang, but a quick Google search presented some solutions. It should be easy enough to memoize in Python, but I didn't try. I have no problem imagining that its running time could come down to 7 seconds or less (maybe even Ruby 1.9's 2.7 seconds).&lt;/p&gt;&lt;p style="clear: both"&gt;If a &lt;em&gt;language&lt;/em&gt; is to be declared a winner, I nominate Erlang. To get that kind of performance when the code implied explicit arrays, I'm impressed.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7671434761870155876?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7671434761870155876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7671434761870155876' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7671434761870155876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7671434761870155876'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/03/collatz-numbers-project-euler-problem.html' title='Collatz Numbers (Project Euler Problem 14)'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-82451432280309754</id><published>2010-03-18T16:06:00.001-04:00</published><updated>2010-03-18T16:06:44.199-04:00</updated><title type='text'>There's a Reason Logorama Won an Oscar</title><content type='html'>&lt;p style="clear: both"&gt;It's frickin' awesome! From the clip I saw during the Oscars, I got the feeling it was a long music video, but there is a story. Or a series of stories (all in 15 minutes).&lt;/p&gt;&lt;p style="clear: both"&gt;The animation is quite cool. It amazes me how many logos they worked in. Be sure to look for "stealth logos", logos that are right in front of you but aren't immediately recognized as logos. (I'm guessing that's one of the purposes of the short.)&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;span style=" display: inline; float: left; margin: 0 10px 10px 0;"&gt;&lt;object height="300" width="400"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=10149605&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /&gt;&lt;embed allowfullscreen="true" type="application/x-shockwave-flash" src="http://vimeo.com/moogaloop.swf?clip_id=10149605&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" allowscriptaccess="always" height="300" width="400"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/span&gt;&lt;br style="clear: both" /&gt;&lt;a href="http://vimeo.com/10149605"&gt;Logorama&lt;/a&gt; from &lt;a href="http://vimeo.com/user3365583"&gt;Marc Altshuler - Human Music&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-82451432280309754?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/82451432280309754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=82451432280309754' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/82451432280309754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/82451432280309754'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/03/there-reason-logorama-won-oscar.html' title='There&amp;#39;s a Reason Logorama Won an Oscar'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2428545569832157341</id><published>2010-03-08T14:12:00.001-05:00</published><updated>2010-03-08T14:12:39.871-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humor'/><category scheme='http://www.blogger.com/atom/ns#' term='recommendation'/><title type='text'>Darwin Weighs in on the Computer</title><content type='html'>&lt;p style="clear: both"&gt;I've been following the &lt;a href="http://sydneypadua.com/2dgoggles/" target="_blank"&gt;2D Goggles blog&lt;/a&gt;, which is a comic about Charles Babbage and Augusta Lovelace. I find it quite amusing, especially Lovelace's pipe smoking. &lt;a href="http://sydneypadua.com/2dgoggles/the-organist-pt-3/" target="_blank"&gt;Today's entry&lt;/a&gt; directed me to &lt;a href="http://www.darwinproject.ac.uk/entry-428" target="_blank"&gt;this letter from Charles Darwin to Charles Lyell&lt;/a&gt;. I find this comment from Darwin quite amusing:&lt;/p&gt;&lt;blockquote style="clear: both"&gt;&lt;p&gt;what a grievous pity it is that [Babbage] should be so implacable, &amp;amp; if one might so call the calculating machine, so very silly.&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="clear: both"&gt;What a rude thing to say about the machine that's proving your theory, Mr. Darwin! (And what great insight and progress 150 years provide!)&lt;/p&gt;&lt;p style="clear: both"&gt;In an aside, just how many scientists back then were named "Charles"?&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2428545569832157341?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2428545569832157341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2428545569832157341' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2428545569832157341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2428545569832157341'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/03/darwin-weighs-in-on-computer.html' title='Darwin Weighs in on the Computer'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4627488623689797257</id><published>2010-03-03T16:22:00.001-05:00</published><updated>2010-03-03T16:22:17.168-05:00</updated><title type='text'>Uh, Yes I DID Define that Cucumber Step!</title><content type='html'>&lt;p style="clear: both"&gt;A couple months back I blogged about putting &lt;a href="http://jdfrens.blogspot.com/2009/12/cucumber-features-in-folders.html" target="_blank"&gt;Cucumber features for a Ruby on Rails project into subfolders&lt;/a&gt;. I finally got around to doing this, and I decided to organize by controller (not by user).&lt;/p&gt;&lt;p style="clear: both"&gt;One reason that it took me a while to make this change was that it didn't work too well the first time I tried it. Running all the Cucumber features worked fine, but running just one feature file would result in a lot of "step not defined" errors—Cucumber couldn't find my files in the support folder.&lt;/p&gt;&lt;p style="clear: both"&gt;More recently, Cucumber added a feature where it keeps track of the scenarios that fail, and when you rerun the &lt;code&gt;cucumber&lt;/code&gt; rake task, just those scenarios are run. It's a cool feature, but it too broke when I put my feature files into subfolders.&lt;/p&gt;&lt;p style="clear: both"&gt;Now I should admit that I'm using &lt;a href="http://www.jetbrains.com/ruby/index.html" target="_blank"&gt;RubyMine&lt;/a&gt;. I'm not ashamed of using it; far from it! It's awesome! However, my problem might be a RubyMine issue, although I doubt it.&lt;/p&gt;&lt;p style="clear: both"&gt;The solution was to tweak the &lt;code&gt;config/cucumber.yml&lt;/code&gt; file.  Here's mine:&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;span style="  display: inline; float: left; margin: 0 10px 10px 0;"&gt;&lt;script src="http://gist.github.com/321037.js?file=cucumber.yml"&gt;&lt;/script&gt;&lt;/span&gt;&lt;br style="clear: both" /&gt;The change is adding &lt;code&gt;-r features/support -r features/step_definitions&lt;/code&gt; to the &lt;code&gt;std_opts&lt;/code&gt;.  I suspect this might mean that those files are included twice when Cucumber is run normally, but that hasn't been a problem yet.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4627488623689797257?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4627488623689797257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4627488623689797257' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4627488623689797257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4627488623689797257'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/03/uh-yes-i-did-define-that-cucumber-step.html' title='Uh, Yes I DID Define that Cucumber Step!'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-675159521122366932</id><published>2010-01-25T14:45:00.001-05:00</published><updated>2010-01-25T14:45:59.147-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='awesome'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Programming with Screenshots</title><content type='html'>&lt;p style="clear: both"&gt;I'm really not sure what to think about this yet: &lt;a href="http://sikuli.org/" target="_blank"&gt;Sikuli&lt;/a&gt; "is a visual technology to search and automate graphical user interfaces (GUI) using images (screenshots)". In the demo on their homepage, they use Sikuli to configure the IP settings on a Mac going through the standard System Preferences app.&lt;/p&gt;&lt;p style="clear: both"&gt;While the underlying technology is Jython (Python running on the JVM), Sikuli is much more visual: whenever they need to specify a target of a click, &lt;em&gt;they take a screenshot&lt;/em&gt;.&lt;/p&gt;&lt;p style="clear: both"&gt;There are somethings in iTunes I'd like to automate, but I'm not quite sure this is the solution. It's kind of intriguing, though.&lt;/p&gt;&lt;p style="clear: both"&gt;And, officially I'd like to tag this under "awesome?", but I'm not sure I want both "awesome" and "awesome?" tags.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-675159521122366932?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/675159521122366932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=675159521122366932' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/675159521122366932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/675159521122366932'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/programming-with-screenshots.html' title='Programming with Screenshots'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3769924181559461957</id><published>2010-01-22T15:54:00.001-05:00</published><updated>2010-01-22T15:54:37.345-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='null'/><title type='text'>Null Objects and Black Holes</title><content type='html'>&lt;p style="clear: both"&gt;The &lt;a href="http://www.pragprog.com/magazines/download/7.pdf" target="_blank"&gt;latest issue of PragPub&lt;/a&gt; (January 2010, &lt;a href="http://www.pragprog.com/magazines" target="_blank"&gt;available in other formats&lt;/a&gt;) has an article in it about &lt;code&gt;nil&lt;/code&gt;, null objects, and black holes. The article is called "Much Ado about Nothing", and it's by Paolo Perrotta. Perrotta presents a problem where a data item might be nil:&lt;/p&gt;&lt;pre style="clear: both"&gt;  CONFIGURATION.current_user.device
&lt;/pre&gt;&lt;p style="clear: both"&gt;What if &lt;code&gt;device&lt;/code&gt; returns &lt;code&gt;nil&lt;/code&gt;?  Any method applied to the device will result in "method not found" errors.&lt;/p&gt;&lt;p style="clear: both"&gt;Perrotta's null-object solution is to return a null device with empty methods:&lt;/p&gt;&lt;pre style="clear: both"&gt;class NullDevice
  def flash; end
  def ring; end
end

  # original code becomes...
  CONFIGURATION.current_user.device || NullDevice.new
&lt;/pre&gt;&lt;p style="clear: both"&gt;I don't like this solution for two reasons. First, is it really fair to let &lt;code&gt;flash&lt;/code&gt; and &lt;code&gt;ring&lt;/code&gt; go through a null device as if they succeeded? It seems to me that if I ring a device, then the owner of that device has been notified of some event. If the current user doesn't have a device, he can't be notified.  If being notified is Very Important, that's a big problem!&lt;/p&gt;&lt;p style="clear: both"&gt;My second dislike is an extension of my first: if you're getting a &lt;code&gt;nil&lt;/code&gt; or a null object, there's a problem. The "method missing" errors in Ruby and &lt;code&gt;NullPointerExeception&lt;/code&gt;s in Java are &lt;em&gt;great&lt;/em&gt; because they tell me that something is wrong. They're &lt;em&gt;terrible&lt;/em&gt; because they're so generic.  I'd prefer to define &lt;code&gt;ring&lt;/code&gt; and &lt;code&gt;flash&lt;/code&gt; to throw exceptions with descriptions of their context.&lt;/p&gt;&lt;p style="clear: both"&gt;Perrotta's final solution (after a couple more iterations) is to do away with the &lt;code&gt;NullDevice&lt;/code&gt; and inject new behavior into the standard &lt;code&gt;NilClass&lt;/code&gt;:&lt;/p&gt;&lt;pre style="clear: both"&gt;class NilClass
  def method_missing(*); self; end
end  
&lt;/pre&gt;&lt;p style="clear: both"&gt;This is what is called a "black hole". Once you're in, you can't get out:&lt;/p&gt;&lt;pre style="clear: both"&gt;nil.ring.ring.ring.flash.flash&lt;/pre&gt;&lt;p style="clear: both"&gt;While I've been known to add new methods to standard classes like &lt;code&gt;Integer&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; and &lt;code&gt;Array&lt;/code&gt;, messing with &lt;code&gt;NilClass&lt;/code&gt; and especially overriding &lt;code&gt;method_missing&lt;/code&gt; seems &lt;em&gt;really&lt;/em&gt; dangerous to me.  I find it really dangerous since now &lt;em&gt;all&lt;/em&gt; &lt;code&gt;nil&lt;/code&gt;s &lt;em&gt;everywhere&lt;/em&gt; in your program will gracefully ignore &lt;em&gt;any&lt;/em&gt; method sent to it.&lt;/p&gt;&lt;p style="clear: both"&gt;All I'm going to say is: if you get a &lt;code&gt;nil&lt;/code&gt; early in your computation, good luck debugging that!&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3769924181559461957?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3769924181559461957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3769924181559461957' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3769924181559461957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3769924181559461957'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/null-objects-and-black-holes.html' title='Null Objects and Black Holes'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-6276386546496290589</id><published>2010-01-20T13:17:00.002-05:00</published><updated>2010-08-19T13:44:45.609-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='system administration'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='parrot'/><title type='text'>Installing Parrot on Mac OSX</title><content type='html'>&lt;p style="clear: both"&gt;&lt;a href="http://www.parrot.org/" target="_blank"&gt;Parrot&lt;/a&gt; is the virtual machine for Perl 6 (and other front ends). I've been using it as a target for &lt;a href="http://github.com/jdfrens/hobbes" target="_blank"&gt;my compiler&lt;/a&gt;. The Parrot people released 2.0.0, so I decided to install it. I always have to remind myself how I installed it last time, so I figured I'd slap my process up on my blog so that I can find it again (and maybe help out someone else).&lt;/p&gt;&lt;p style="clear: both"&gt;A few notes: &lt;/p&gt;&lt;ul style="clear: both"&gt;&lt;li&gt;The MacPorts version of Parrot is kind of old; I played with the Portfile for a while (even helped get it up to version 1.0.0), but there are really odd linking issues. I've just found it easier installing by hand.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I am using &lt;code&gt;gmake&lt;/code&gt; from MacPorts.  I believe I ran into an issue once where this was important.&lt;/li&gt;&lt;li&gt;I use /usr/local (the default) as the installation prefix. I use /usr/local/src as my compilation area.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I've tried other configuration flags like &lt;code&gt;--jitcapable&lt;/code&gt; and &lt;code&gt;--execcapable&lt;/code&gt;. I believe that the former isn't recommended at all (the JIT compiler is in a state of flux); I forget why I stopped using the latter.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The Parrot libraries of a previous installation confuses the new compilation.  Hence, I remove all the &lt;code&gt;libparrot&lt;/code&gt;s I can find.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Here are commands I executed this last time:&lt;br /&gt;&lt;pre style="clear: both"&gt;cd /usr/local/src/
mv ~/Downloads/parrot-2.0.0.tar.gz .
tar xvzf parrot-2.0.0.tar.gz 
cd parrot-2.0.0
sudo rm /usr/local/lib/libparrot.*
perl Configure.pl --optimize
gmake
gmake test
sudo gmake install &lt;/pre&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-6276386546496290589?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/6276386546496290589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=6276386546496290589' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6276386546496290589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6276386546496290589'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/installing-parrot-on-mac-osx.html' title='Installing Parrot on Mac OSX'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3743385856293887164</id><published>2010-01-14T13:02:00.000-05:00</published><updated>2010-01-14T13:02:00.220-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='quadtree matrices'/><title type='text'>Not a Num Instance?</title><content type='html'>&lt;p style="clear: both"&gt;I've presented Haskell code for quadtree-matrix operations &lt;a href="http://jdfrens.blogspot.com/2009/12/original-quadtree-matrix-algorithms.html" target="_blank"&gt;addition&lt;/a&gt; and &lt;a href="http://jdfrens.blogspot.com/2010/01/matrix-matrix-multiplication-with-quadtrees-in-haskell.html" target="_blank"&gt;multiplication&lt;/a&gt;. I implemented these algorithms as an instance of the &lt;a href="http://haskell.org/ghc/docs/latest/html/libraries/base-4.2.0.0/Prelude.html#7" target="_blank"&gt;&lt;code&gt;Num&lt;/code&gt; typeclass&lt;/a&gt;. Haskell is strongly typed, and &lt;a href="http://www.haskell.org/tutorial/classes.html" target="_blank"&gt;type classes&lt;/a&gt; provide overloading (a.k.a. &lt;em&gt;ad hoc&lt;/em&gt; polymorphism). For example, a numeric type will most likely want to use the &lt;code&gt;+&lt;/code&gt; operator. Haskell manages the different definitions of &lt;code&gt;+&lt;/code&gt; (one for integers, one for floating-point numbers, one for complex numbers, etc.) through &lt;em&gt;instances&lt;/em&gt; the &lt;code&gt;Num&lt;/code&gt; class. The &lt;code&gt;Integer&lt;/code&gt; type is a &lt;code&gt;Num&lt;/code&gt; instance by using an integer addition instruction; the &lt;code&gt;Double&lt;/code&gt; type is a &lt;code&gt;Num&lt;/code&gt; instance by using a floating-point addition instruction; the &lt;code&gt;Complex&lt;/code&gt; type is a num instance by recursively calling &lt;code&gt;+&lt;/code&gt; on the real and imaginary components of the complex numbers.&lt;/p&gt;&lt;p style="clear: both"&gt;The problem I have with making my &lt;code&gt;Matrix&lt;/code&gt; type a &lt;code&gt;Num&lt;/code&gt; instance mostly comes down to all of the functions that need to be declared: &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;negate&lt;/code&gt;, &lt;code&gt;abs&lt;/code&gt;, &lt;code&gt;signum&lt;/code&gt;, and &lt;code&gt;fromInteger&lt;/code&gt;.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;ul style="clear: both"&gt;&lt;li&gt;The first three functions can be defined just fine on matrices. &lt;br /&gt;&lt;/li&gt;&lt;li&gt;Negating a matrix isn't quite as obvious, but multiplying all of the elements of the matrix by -1 seems reasonable. But is it useful? I doubt it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;What about &lt;code&gt;abs&lt;/code&gt;? What is the absolute value of a matrix? There are some possibilities (maybe the &lt;a href="http://en.wikipedia.org/wiki/Determinant" target="_blank"&gt;determinant&lt;/a&gt;), but none are pleasing. &lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;signum&lt;/code&gt; (is the number less than, equal to, or greater than zero) is impossible to define in a meaningful way. &lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;fromInteger&lt;/code&gt; isn't too bad: turn the integer into a scalar matrix (or the zero matrix).&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;The &lt;code&gt;Num&lt;/code&gt; class only deals with matrix-matrix operations. I would also like to have scalar-matrix and vector-matrix and matrix-vector operations. Implementing a &lt;code&gt;Num&lt;/code&gt; instance wouldn't preclude these other types of operations, but it feels a bit awkward to me.  (It's worth noting that the &lt;code&gt;Num&lt;/code&gt; class forces the operands to &lt;code&gt;+&lt;/code&gt; to be the same type, e.g., both matrices, not a matrix and a vector.)  I suspect I'll grapple with this issue more as I delve more into bigger, higher level algorithms.&lt;/p&gt;&lt;p style="clear: both"&gt;I'm not completely ready to abandon &lt;code&gt;Matrix&lt;/code&gt; as an instance of the &lt;code&gt;Num&lt;/code&gt; class because of what I might lose. That is, thousands of other Haskell programmers have implemented algorithms that rely solely on the &lt;code&gt;Num&lt;/code&gt; type class. For me to plug in my &lt;code&gt;Matrix&lt;/code&gt; type without any extra work, I need to implement &lt;code&gt;Matrix&lt;/code&gt; as an instance of the &lt;code&gt;Num&lt;/code&gt; class.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3743385856293887164?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3743385856293887164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3743385856293887164' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3743385856293887164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3743385856293887164'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/not-num-instance.html' title='Not a Num Instance?'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-808001737158048377</id><published>2010-01-13T13:01:00.000-05:00</published><updated>2010-01-13T13:01:00.303-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='quadtree matrices'/><title type='text'>Matrix-Matrix Multiplication with Quadtrees in Haskell</title><content type='html'>&lt;p style="clear: both"&gt;The last time I spent a recess break on quadtree matrices, it was mostly &lt;a href="http://jdfrens.blogspot.com/2009/12/original-quadtree-matrix-algorithms.html"&gt;to present matrix-matrix addition&lt;/a&gt;. Today I present matrix-matrix multiplication.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h3&gt;The Algorithm&lt;/h3&gt;&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;em&gt;C = A * B&lt;/em&gt; is often presented at the element level. That is, &lt;em&gt;c&lt;sub&gt;ij&lt;/sub&gt;&lt;/em&gt; is computed by multiplying the elements of row &lt;em&gt;A&lt;sub&gt;i&lt;/sub&gt;&lt;/em&gt; by the elements of column &lt;em&gt;B&lt;sub&gt;j&lt;/sub&gt;&lt;/em&gt; and adding those products together. Wikipedia presents &lt;a href="http://en.wikipedia.org/wiki/Matrix_multiplication" target="_blank"&gt;a good description with pictures&lt;/a&gt;. The cool thing is that this works at the quadtree level. To compute &lt;em&gt;C&lt;sub&gt;nw&lt;/sub&gt;&lt;/em&gt;, you multiply &lt;em&gt;A&lt;sub&gt;nw&lt;/sub&gt;&lt;/em&gt; by &lt;em&gt;B&lt;sub&gt;nw&lt;/sub&gt;&lt;/em&gt; and &lt;em&gt;A&lt;sub&gt;ne&lt;/sub&gt;&lt;/em&gt; by &lt;em&gt;B&lt;sub&gt;sw&lt;/sub&gt;&lt;/em&gt;, then add those products together.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;h3&gt;Instance of the Num Class&lt;/h3&gt;&lt;/p&gt;&lt;pre style="clear: both"&gt;instance (Eq a, Num a) =&amp;gt; Num (Matrix a) where
  ZeroM * _ = ZeroM
  _ * ZeroM = ZeroM
  ScalarM a * ScalarM b = ScalarM (a*b)
  QuadM (nwA, neA, swA, seA) * QuadM (nwB, neB, swB, seB) =
    normalize $ QuadM (nwA * nwB + neA * swB
                      ,nwA * neB + neA * seB
                      ,swA * nwB + seA * swB
                      ,swA * neB + seA * seB)
  _ * _ = error "invalid arguments"
  -- other Num definitions&lt;/pre&gt;&lt;p style="clear: both"&gt;Again, &lt;code&gt;normalize&lt;/code&gt; is supposed to normalize the representation, making sure all "zero matrices" are represented by a &lt;code&gt;ZeroM&lt;/code&gt;.  There's a potential bug here if we use numbers very close to zero; multiplying two numbers really close to zero results in a product that's &lt;em&gt;really&lt;/em&gt; close to zero.  So close, we might want to consider it zero.  This is easily fixed by adding a call to &lt;code&gt;normalize&lt;/code&gt; in the scalar case.&lt;/p&gt;&lt;p style="clear: both"&gt;I actually implemented it a bit differently in &lt;a href="http://github.com/jdfrens/quadtrees/blob/beff63c150d8947796e35d441438895442430a7d/src/Data/Quadtrees.hs" target="_blank"&gt;my actual code&lt;/a&gt;. The difference is in the scalar case:&lt;/p&gt;&lt;pre style="clear: both"&gt;  QuadM a@(nwA, neA, swA, seA) * QuadM (nwB, neB, swB, seB) =
    normalize $ QuadM $ zipQuads (+) (zipQuads (*) x y) (zipQuads (*) a z)
      where x = (neA, nwA, seA, swA)
            y = (swB, neB, swB, neB)
            z = (nwB, seB, nwB, seB)
&lt;/pre&gt;&lt;p style="clear: both"&gt;There are those &lt;code&gt;zipQuads&lt;/code&gt; that I've suggested mean "parallelism!!!".  I find the quadrant shuffling here a bit confusing though.&lt;/p&gt;&lt;p style="clear: both"&gt;Next time I'll talk about why I dislike implementing the quadtree &lt;code&gt;Matrix&lt;/code&gt; type as an instance of the &lt;code&gt;Num&lt;/code&gt; class.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-808001737158048377?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/808001737158048377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=808001737158048377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/808001737158048377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/808001737158048377'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/matrix-matrix-multiplication-with.html' title='Matrix-Matrix Multiplication with Quadtrees in Haskell'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-6400087938278774427</id><published>2010-01-11T13:59:00.001-05:00</published><updated>2010-01-11T13:59:03.736-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='system administration'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Apache Errors on a MacBook</title><content type='html'>&lt;p style="clear: both"&gt;If the default Apache server on your OS X machine isn't working and if &lt;code&gt;/var/log/apache2/error_log&lt;/code&gt; isn't showing any errors, check the Console app. It'll tell you if a configuration file has a syntax error in it.  I expected syntax errors to show on the command line when I start/restart (as they do on most Linux systems).&lt;/p&gt;&lt;p style="clear: both"&gt;Live and learn. Avoid my pain.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-6400087938278774427?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/6400087938278774427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=6400087938278774427' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6400087938278774427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6400087938278774427'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/apache-errors-on-macbook.html' title='Apache Errors on a MacBook'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8867781386521668514</id><published>2010-01-10T13:10:00.000-05:00</published><updated>2010-01-10T13:10:00.412-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='aop'/><title type='text'>Possibly Useful Use Case for RCapture</title><content type='html'>&lt;p style="clear: both"&gt;I &lt;a href="http://jdfrens.blogspot.com/2010/01/aspect-oriented-programming-in-ruby.html" target="_blank"&gt;blogged&lt;/a&gt; the other day about &lt;a href="http://cheind.wordpress.com/2010/01/07/introducing-rcapture/" target="_blank"&gt;a blog post from Christoph Heindl&lt;/a&gt; on his new Ruby gem, &lt;a href="http://code.google.com/p/rcapture/" target="_blank"&gt;RCapture&lt;/a&gt;. I lamented a bit that I've not found aspect oriented programming to be useful in general, and the debugging and logging use cases are not impressive to me.&lt;/p&gt;  &lt;p style="clear: both"&gt;However, RCapture might have a use case I can get behind since it takes advantage of Ruby blocks. In developing some of my Ruby libraries, I've tried to deal with constructors that need to take a &lt;em&gt;lot&lt;/em&gt; of arguments. Should &lt;code&gt;initialize&lt;/code&gt; have fifteen positional parameters? Then I have to remember the order of those parameters. Initialize with an options hash? That makes calling the method more work (unless there are a lot of default values).  I've fallen in love with a pattern where &lt;code&gt;initialize&lt;/code&gt; yields to the block passed to it, passing in &lt;code&gt;self&lt;/code&gt; as an argument.  RSpec lets you specify a rake task using this approach:&lt;/p&gt;  &lt;pre style="clear: both"&gt;Spec::Rake::SpecTask.new do |t|
  t.warning = true
  t.rcov = true
end
&lt;/pre&gt;  &lt;p style="clear: both"&gt;I like the syntax of this block, and I find myself using this more and more. I get frustrated when a library doesn't define &lt;code&gt;initialize&lt;/code&gt; to work this way.  But now, RCapture allows me to add it.  Suppose my library defines this:&lt;/p&gt;  &lt;pre style="clear: both"&gt;class X
  attr_accessor :name  # and 14 more reader/writer attributes
  def initialize(options={})
    @name = options[:name] || "foobar"
    # 14 other initializations from options
  end
end
&lt;/pre&gt;  &lt;p style="clear: both"&gt;All the programmer would have to do is add &lt;code&gt;yield self if block_given?&lt;/code&gt; at the end of &lt;code&gt;initialize&lt;/code&gt; to make me happy.  But instead, I'm stuck using the options hash, and this syntax is not as nice. Until I use RCapture:&lt;/p&gt;  &lt;pre style="clear: both"&gt;require 'rcapture'

class X
  include RCapture::Interceptable
end

X.capture :class_methods =&amp;gt; :new do |ci|
  ci.block.call(ci.return) if ci.block
end

jdfrens = X.new do |x|
  x.name = "jdfrens"
end
&lt;/pre&gt;  &lt;pre style="clear: both"&gt;jdfrens.name  # =&amp;gt; "jdfrens"&lt;/pre&gt;  &lt;p style="clear: both"&gt;I get to use the syntax I like. Of course, it's not foolproof. I'm now relying on the default values as specified in &lt;code&gt;initialize&lt;/code&gt; before I override them, and if they create objects or do any significant work, that's a problem. I could balance this out by specifying some things in the hash and the others in the block. Also, this trick won't work (easily) for positional parameters; they'll still have to be given as arguments.&lt;/p&gt;  &lt;p style="clear: both"&gt;This is certainly not a "killer use case" for RCapture, but it makes me wonder what other uses it might have.&lt;/p&gt;  &lt;br class="final-break" style="clear: both" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8867781386521668514?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8867781386521668514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8867781386521668514' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8867781386521668514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8867781386521668514'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/possibly-useful-use-case-for-rcapture.html' title='Possibly Useful Use Case for RCapture'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8653201668458957281</id><published>2010-01-09T13:03:00.001-05:00</published><updated>2010-01-09T13:03:00.222-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='animation'/><category scheme='http://www.blogger.com/atom/ns#' term='awesome'/><title type='text'>Frakkin' Amazing Animation</title><content type='html'>&lt;p style="clear: both"&gt;Is 12 minutes too long for a recess break on Saturday? Make time for this (HD available on Vimeo, well worth it):&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;span style=" display: inline; float: left; margin: 0 10px 10px 0;"&gt;&lt;object height="225" width="400"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=7809605&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /&gt;&lt;embed allowfullscreen="true" type="application/x-shockwave-flash" src="http://vimeo.com/moogaloop.swf?clip_id=7809605&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" allowscriptaccess="always" height="225" width="400"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/span&gt;&lt;br style="clear: both" /&gt;&lt;a href="http://vimeo.com/7809605"&gt;The Third &amp;amp; The Seventh&lt;/a&gt; from &lt;a href="http://vimeo.com/user1337612"&gt;Alex Roman&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;. &lt;/p&gt;&lt;p style="clear: both"&gt;All CG. No really, that's what the person behind this video claims. Certainly some of the scenes at the end are pretty unbelievable, but I challenge you to find a flaw in his trees. Amazing.&lt;/p&gt;&lt;p style="clear: both"&gt;If you have the time, check out this compositing breakdown (3 minutes):&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;span style=" display: inline; float: left; margin: 0 10px 10px 0;"&gt;&lt;object height="300" width="400"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=8200251&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /&gt;&lt;embed allowfullscreen="true" type="application/x-shockwave-flash" src="http://vimeo.com/moogaloop.swf?clip_id=8200251&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" allowscriptaccess="always" height="300" width="400"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/span&gt;&lt;br style="clear: both" /&gt;&lt;a href="http://vimeo.com/8200251"&gt;Compositing Breakdown (T&amp;amp;S)&lt;/a&gt; from &lt;a href="http://vimeo.com/user1337612"&gt;Alex Roman&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8653201668458957281?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8653201668458957281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8653201668458957281' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8653201668458957281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8653201668458957281'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/frakkin-amazing-animation.html' title='Frakkin&amp;#39; Amazing Animation'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2010470768914695950</id><published>2010-01-08T13:01:00.000-05:00</published><updated>2010-01-08T13:01:00.477-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='aop'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>Aspect Oriented Programming in Ruby</title><content type='html'>&lt;p style="clear: both"&gt;My Twitter feed delivered this article to me: &lt;a href="http://cheind.wordpress.com/2010/01/07/introducing-rcapture/"&gt;"Introducing RCapture"&lt;/a&gt; by Christoph Heindl. RCapture, without really admitting it, is a library for some basic &lt;a href="http://en.wikipedia.org/wiki/Aspect_oriented_programming" target="_blank"&gt;aspect oriented programming&lt;/a&gt; (AOP) in Ruby.&lt;/p&gt;&lt;p style="clear: both"&gt;The basic idea behind AOP is that you add &lt;strong&gt;aspects&lt;/strong&gt; to your code which are executed before or after (or during?) existing methods. Aspects are written &lt;em&gt;separately&lt;/em&gt; from the original code. Let me use an RCapture example (slightly modified from Heindl's post):&lt;/p&gt;&lt;pre style="clear: both"&gt;Array.capture_post :methods =&amp;gt; [:push] do |cs|
  puts "#{cs.args.first} was pushed to array #{cs.sender}"
end
&lt;/pre&gt;&lt;p style="clear: both"&gt;&lt;code&gt;capture_post&lt;/code&gt; is the RCapture method.  Called on the &lt;code&gt;Array&lt;/code&gt; class, this says that after ("&lt;code&gt;post&lt;/code&gt;") the &lt;code&gt;push&lt;/code&gt; method is called, the block should be executed.  &lt;code&gt;cs&lt;/code&gt;, the argument of the block, holds the environment for the method call, which is used in the output message.&lt;/p&gt;&lt;p style="clear: both"&gt;The best use cases I've heard for AOP is for logging and debugging. The example above is a debugging example. It would be just as easy to use a logger instead. But why not add the debugging and logging code to &lt;code&gt;Array#push&lt;/code&gt; itself?  That's the power of AOP: separation of concerns.  Separate out the debugging and logging from the business logic.  It keeps the code cleaner, and makes the aspected code optional (just don't include that module).&lt;/p&gt;&lt;p style="clear: both"&gt;I've played around with AOP, but it's never struck me as something &lt;em&gt;that&lt;/em&gt; useful. For my favorite use cases, debugging is better done with a debugger, and logging is not really a terrible clutter in business logic.&lt;/p&gt;&lt;p style="clear: both"&gt;The one weakness I see with RCapture is its limited pointcuts language. A &lt;strong&gt;pointcut&lt;/strong&gt; is a description of when and where an aspect is to be triggered. RCapture has the simplest possible: name a class, name some methods, indicate "pre" or "post". &lt;a href="http://www.eclipse.org/aspectj/" target="_blank"&gt;AspectJ&lt;/a&gt;, an AOP extension to Java, has a very expressive language for pointcuts.  For example, &lt;code&gt;execution(* set*(*))&lt;/code&gt; is an AspectJ pointcut for an aspect during the execution of &lt;em&gt;any&lt;/em&gt; method that &lt;em&gt;begins&lt;/em&gt; with "&lt;code&gt;set&lt;/code&gt;" that has &lt;em&gt;one&lt;/em&gt; argument of &lt;em&gt;any&lt;/em&gt; type and returns a value of &lt;em&gt;any&lt;/em&gt; type.&lt;/p&gt;&lt;p style="clear: both"&gt;I'm not sure that this is a bad weakness, though. RCapture does have a filter option for refining when an aspect should be triggered. AspectJ's language for pointcuts seems a little too powerful to me, that it'd be too easy to write a pattern that matched too many points.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2010470768914695950?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2010470768914695950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2010470768914695950' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2010470768914695950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2010470768914695950'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/aspect-oriented-programming-in-ruby.html' title='Aspect Oriented Programming in Ruby'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4822239369371244755</id><published>2010-01-07T13:04:00.000-05:00</published><updated>2010-01-07T13:04:00.184-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='inheritance'/><category scheme='http://www.blogger.com/atom/ns#' term='ood'/><category scheme='http://www.blogger.com/atom/ns#' term='lsp'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>Barbara Liskov's Turing Award Talk (at OOPSLA)</title><content type='html'>&lt;p style="clear: both"&gt;Another presentation for you to watch during recess: &lt;a href="http://www.infoq.com/presentations/liskov-power-of-abstraction"&gt;The Power of Abstraction&lt;/a&gt; by Barbara Liskov. Liskov &lt;a href="http://www.acm.org/press-room/news-releases/turing-award-08"&gt;won the Turing Award in 2008&lt;/a&gt;. The presentation comes from InfoQ; here's their summary:&lt;/p&gt;&lt;blockquote style="clear: both"&gt;&lt;p&gt;In a reprise of her ACM Turing Award lecture, Barbara Liskov discusses the invention of abstract data types, the CLU programming language, clusters, polymorphism, exception handling, iterators, implementation inheritance, type hierarchies, the Liskov Substitution Principle, polymorphism, and future challenges such as new abstractions, parallelism, and the Internet.&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="clear: both"&gt;&lt;strong&gt;CLU.&lt;/strong&gt; Much of the talk is a historical account of why and how &lt;a href="http://en.wikipedia.org/wiki/CLU_(programming_language)"&gt;CLU&lt;/a&gt; came about. I get the feeling that the 1970s were a really heady time for programming languages based on the papers she listed as motivation (including Djikstra's "GOTO Statement Considered Harmful", see a near-complete &lt;a href="http://www.cincomsmalltalk.com/userblogs/ralph/blogView?showComments=true&amp;amp;printTitle=OOPSLA,_first_day&amp;amp;entry=3434162533"&gt;list of papers&lt;/a&gt; collected Ralph Johnson).&lt;/p&gt;&lt;p style="clear: both"&gt;CLU did have some interesting features (for the early 1970s): exception handling and iterators. I wish I had been taught exception handling from the very beginning since it's such as easier way to handle edge cases. And I hate FORTRAN and C for foisting their counting for loops on us for array processing; I much prefer iterators.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;strong&gt;Reading Programs. &lt;/strong&gt; One observation she made, more than once at different times in the talk and during the Q&amp;amp;A, in the 1970s it was important to make programs easier to &lt;em&gt;write&lt;/em&gt;, but today we must make programs easier to &lt;em&gt;read&lt;/em&gt;. (Based on how strongly she felt about this, I'm not surprised that CLU's syntax is no longer used... not readable!) I've heard this "code must be readable" more and more, especially from the Ruby community. It was nice hearing Liskov reiterating this issue from a historical perspective.&lt;/p&gt;&lt;p style="clear: both"&gt;&lt;strong&gt;LSP.&lt;/strong&gt; Liskov then spends some time on the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov Substitution Principle&lt;/a&gt; (LSP). She makes a very important observation: inheritance is used for two different things, (1) implementation and (2) type hierarchies. At the time she wrote her paper, people were &lt;em&gt;really&lt;/em&gt; confused over type hierarchies; someone wrote a paper that said stacks and queues were subtypes of a common type! The base type had "add" and "remove" actions; the stack and queue implementations would do their own things. Based on the LSP, the cumulative behaviors of "add" and "remove" are very different (e.g., add two items, remove one, different answers!), and so this overabstraction is judged invalid. Fortunately, it seems really odd to me now that people were confused over this.&lt;/p&gt;&lt;p style="clear: both"&gt;I've blogged briefly on the implementation violation of LSP (&lt;a href="http://jdfrens.blogspot.com/2006/11/square-does-not-extend-rectangle.html"&gt;"Square Does Not Extend Rectangle!"&lt;/a&gt;), and it bugs me how often I encounter this type of violation, at least when I was in the academic world. There's a question at the very end of the Q&amp;amp;A session directly on this point. A recent graduate commented that she had been taught the bad hierarchy in class, and she was set straight at an internship. Liskov describes what she does at MIT (teaching LSP in a second semester course in Java), but she didn't address the issue of how to stop these evil professors and textbook authors from foisting yet another shape or employee hierarchy on students.&lt;/p&gt;&lt;p style="clear: both"&gt;It's a good talk, and if you have 80 minutes to spend, it's worth your time.&lt;/p&gt;&lt;br class='final-break' style='clear: both' /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4822239369371244755?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4822239369371244755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4822239369371244755' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4822239369371244755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4822239369371244755'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/barbara-liskov-turing-award-talk-at.html' title='Barbara Liskov&amp;#39;s Turing Award Talk (at OOPSLA)'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-15352268115212663</id><published>2010-01-06T12:01:00.000-05:00</published><updated>2010-01-06T12:01:00.168-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Eat Some More Cucumbers</title><content type='html'>&lt;p&gt;Here's yet another &lt;a href="http://www.infoq.com/presentations/wilk-cucumber"&gt;presentation on Cucumber&lt;/a&gt;, a DSL and framework for acceptance tests.  This comes from Joseph Wilk (from the Cucumber core) at FutureRuby.&lt;/p&gt;

&lt;p&gt;If you haven't heard the elevator pitch for Cucumber yet, shame on you.  Remedy this by watching this relatively short intro (30 minutes).&lt;/p&gt;

&lt;p&gt;He reminded me of something: Cucumber works with JRuby and therefore the JVM.  I'm wondering how difficult this would be for some of my Java projects...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-15352268115212663?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/15352268115212663/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=15352268115212663' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/15352268115212663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/15352268115212663'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2010/01/eat-some-more-cucumbers.html' title='Eat Some More Cucumbers'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7342677461437012482</id><published>2009-12-26T12:56:00.001-05:00</published><updated>2009-12-26T12:56:08.396-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><title type='text'>Cucumber Features in Folders</title><content type='html'>&lt;p&gt;For today's recess break, I'm thinking about organizing my Cucumber tests in a Ruby on Rails project.&lt;/p&gt;

&lt;p&gt;The webapp has a user system to keep the riffraff from changing content they have no right to change.  I'm using &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; for &lt;a href="http://github.com/jdfrens/calvincs/tree/ec6d653c8d456b74158371de89a765e62fd7e392"&gt;my acceptance tests&lt;/a&gt;, and while I only have 15 features files so far, more are likely.&lt;/p&gt;

&lt;h3&gt;Folder Organization&lt;/h3&gt;

&lt;p&gt;I can (apparently) create subfolders in my &lt;code&gt;features&lt;/code&gt; folder to organize them better.  So my question is this: organize them by type of user (administrator versus guest) or by controller?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By user?&lt;/strong&gt;  Won't it help me mentally separate the two different roles?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By controller?&lt;/strong&gt; This is how the rest of the Rails app is organized, especially the &lt;code&gt;app/views&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;I'm inclined to organize by controller.  Usually I'm working on one controller at a time, switching between the different types of users.&lt;/p&gt;

&lt;h3&gt;Granularity of Features&lt;/h3&gt;

&lt;p&gt;When is a feature file too big?  When do you split a feature file up?  How?&lt;/p&gt;

&lt;p&gt;Splitting based on users is &lt;em&gt;required&lt;/em&gt; by the role and purpose in the opening narrative.  Might one split based on RESTful actions?  That seems too fine grained, although if there a lot of sad paths, a split or two might be prudent as well.&lt;/p&gt;

&lt;h3&gt;Terminology&lt;/h3&gt;

&lt;p&gt;Is anyone else bothered by my use of "folder" instead of "directory"?  Seventeen years of teaching college students who didn't want to learn basic computer usage or "already knew it" has forced me to look for the best metaphors.  "Directory" means &lt;em&gt;nothing&lt;/em&gt; to them.  "Folder" does.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7342677461437012482?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7342677461437012482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7342677461437012482' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7342677461437012482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7342677461437012482'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/12/cucumber-features-in-folders.html' title='Cucumber Features in Folders'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-770480475189799347</id><published>2009-12-23T17:11:00.001-05:00</published><updated>2009-12-23T17:11:48.997-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='quadtree matrices'/><title type='text'>Original Quadtree-Matrix Algorithms</title><content type='html'>&lt;p&gt;For this recess break, I'm going to present the quadtree-matrix algorithm for &lt;a href="http://en.wikipedia.org/wiki/Matrix_addition"&gt;matrix-matrix addition&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Thinking about the Quadtree-Matrix Algorithm&lt;/h3&gt;

&lt;p&gt;To add two matrices, you add the elements component-wise.  Same thing with quadtree matrices, although you base your definition on the recursive definition of a quadtree matrix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If either matrix is zero, return the other.&lt;/li&gt;
&lt;li&gt;If they're both scalars, return their sum.&lt;/li&gt;
&lt;li&gt;Otherwise, add the northwest, northeast, southwest, and southeast quadrants recursively, and return those sums as a new quadtree matrix.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Haskell's &lt;code&gt;Num&lt;/code&gt; Class&lt;/h3&gt;

&lt;p&gt;Haskell has classes.  Just like Java and most object-oriented languages.  &lt;em&gt;And completely unlike them.&lt;/em&gt;  I'm not going to get into the nitty-gritty of type classes in Haskell in this recess break, but suffice it to say that it allows one to overload operators, like &lt;code&gt;+&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Algorithm Implemented as Part of &lt;code&gt;Num&lt;/code&gt; Instance&lt;/h3&gt;

&lt;p&gt;Here's the code.  I'll deconstruct it below.&lt;/p&gt;

&lt;pre&gt;
instance (Eq a, Num a) =&gt; Num (Matrix a) where
  ZeroM + m = m
  m + ZeroM = m
  ScalarM a + ScalarM b = normalize $ ScalarM (a+b)
  QuadM a + QuadM b = normalize $ QuadM $ zipQuads (+) a b
  _ + _ = error "invalid arguments"
  -- many other Num definitions omitted

normalize (ScalarM 0) = ZeroM
normalize (QuadM (ZeroM, ZeroM, ZeroM, ZeroM)) = ZeroM
normalize q = q
 
zipQuads f (nw1, ne1, sw1, se1) (nw2, ne2, sw2, se2) =
  (f nw1 nw2, f ne1 ne2, f sw1 sw2, f se1 se2)
&lt;/pre&gt;

&lt;p&gt;You can see a fuller implementation in &lt;a href="http://github.com/jdfrens/quadtrees/blob/beff63c150d8947796e35d441438895442430a7d/src/Data/Quadtrees.hs"&gt;&lt;code&gt;Quadtree.hs&lt;/code&gt;&lt;/a&gt; from an early commit in my GitHub repository.&lt;/p&gt;

&lt;p&gt;I'm &lt;em&gt;not&lt;/em&gt; going to explain much of this code.  (I'll do that in future recess breaks.)  Let me point out the highlights:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;instance Num (Matrix a)&lt;/code&gt; means that a &lt;code&gt;Matrix&lt;/code&gt; is an instance of the &lt;code&gt;Num&lt;/code&gt; type class, and we have to write a version of &lt;code&gt;+&lt;/code&gt; for &lt;code&gt;Matrix&lt;/code&gt;s.&lt;/li&gt;
  &lt;li&gt;The definition of &lt;code&gt;+&lt;/code&gt; uses &lt;em&gt;pattern matching&lt;/em&gt;.  Instead of asking the first argument if it's zero with a predicate, I write what looking like an actual invocation: &lt;code&gt;ZeroM + m = m&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;ScalarM&lt;/code&gt; and &lt;code&gt;QuadM&lt;/code&gt; are type constructors.  they construct (and pattern match) &lt;code&gt;Matrix&lt;/code&gt;s.  So &lt;code&gt;ScalarM a + ScalarM b&lt;/code&gt; is a pattern for "If the two arguments are scalars...".  &lt;code&gt;ScalarM (a+b)&lt;/code&gt; constructs a new &lt;code&gt;Matrix&lt;/code&gt; consisting of the sum of the two scalars.&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;normalize&lt;/code&gt; function normalizes non-standard representations of zero like &lt;code&gt;ScalarM 0&lt;/code&gt; and &lt;code&gt;QuadM (ZeroM, ZeroM, ZeroM, ZeroM).&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;zipQuads&lt;/code&gt; applies a function to the quadrants of two general quadtree matrices, quadrant-wise.  Generally, when you see &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;zip&lt;/code&gt; in a functional language, think: "This could be done in parallel!"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we can quibble about Haskell syntax and all that, but this Haskell code seems more straightforward to me than the nested loops we write for row/column thinking in C/C++/Java.  And I get parallelism "for free" with the use of &lt;code&gt;zipQuads&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I'll spend some time exploring the Haskellisms in this code, in particular: the syntax and the &lt;code&gt;Num&lt;/code&gt; class (and why I don't like it for my quadtree matrix).  And I'm going to have to justify calling Haskell's type classes similar to Java classes.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-770480475189799347?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/770480475189799347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=770480475189799347' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/770480475189799347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/770480475189799347'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/12/original-quadtree-matrix-algorithms.html' title='Original Quadtree-Matrix Algorithms'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4142216997767480230</id><published>2009-12-22T14:03:00.001-05:00</published><updated>2009-12-22T14:03:02.813-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='quadtree matrices'/><title type='text'>Quadtree Matrices</title><content type='html'>&lt;h3&gt;Matrices&lt;/h3&gt;

&lt;p&gt;I'm going to assume that you know what a matrix is.  (Insert stupid "not &lt;a href="http://en.wikipedia.org/wiki/The_Matrix_%28series%29"&gt;a virtual reality created by robot overlords&lt;/a&gt;" and "not a &lt;a href="http://en.wikipedia.org/wiki/Matrix_%28Doctor_Who%29"&gt;Gallifreyan computer for Time Lord memories&lt;/a&gt;" jokes here.)  If you need a refresher, look up &lt;a href="http://en.wikipedia.org/wiki/Matrix_%28mathematics%29"&gt;matrix&lt;/a&gt; at Wikipedia.&lt;/p&gt;

&lt;p&gt;The important thing to know for this recess break is that matrices are a grid of numbers (or other algebraic entities like polynomials).&lt;/p&gt;

&lt;h3&gt;Quadtrees&lt;/h3&gt;

&lt;p&gt;The Wikipedia article on &lt;a href="http://en.wikipedia.org/wiki/Quadtree"&gt;quadtrees&lt;/a&gt; focuses mostly on geometry applications.  The data structure is the same as for matrices, it's just a matter of what's stored at the leaves.&lt;/p&gt;

&lt;h3&gt;Quadtree Matrices&lt;/h3&gt;

&lt;p&gt;Quadtree matrices are recursive.  The &lt;strong&gt;simple base case&lt;/strong&gt; is that a single number, a &lt;em&gt;scalar&lt;/em&gt;, is a quadtree matrix, a leaf node.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;general, recursive case&lt;/strong&gt; is to take a general matrix, and split it into &lt;em&gt;quadrants&lt;/em&gt;: split the matrix in half horizontally and vertically.  Consider this example from my dissertation:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20091222-1gmb9qsi8qcffhn5awt1fbp1kj.jpg" alt="quadtree data structure" /&gt;&lt;/p&gt;

&lt;p&gt;Look how the quadrant in the upper left, what we call the &lt;em&gt;northwest quadrant&lt;/em&gt;, is found as the first subtree of the quadtree.  The northwest quadrant of that quadrant (the 2.1) is the first subsubtree of the subtree.  Similarly, the &lt;em&gt;northeast&lt;/em&gt; quadrant is second, followed by the &lt;em&gt;southwest&lt;/em&gt; and &lt;em&gt;southeast&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This example also demonstrates what we do with matrices that aren't easily chopped in half all the way down.  We'd like every matrix to have an order which is a power of 2, but that's just not going to happen.  Instead, we pad out each matrix with zeros on the east and south to get the order to a power of 2.  In the example above, it means only adding one column and one row of zeros, but in general many columns and rows of zeros may be added.  But notice in this example that the 0.0 scalars in the original matrix are turned into special leaf nodes, labeled "Z" for "zero", of course.  While all scalars will appear on the same level of the quadtree matrix, a zero leaf can appear anywhere (as another &lt;strong&gt;base case&lt;/strong&gt;), and the space we use is only a log (base 2) compared to storing all of the raw 0.0s.&lt;/p&gt;

&lt;h3&gt;Haskell Code&lt;/h3&gt;

&lt;p&gt;We represent a quadtree matrix in Haskell as an algebraic type.&lt;/p&gt;

&lt;pre&gt;
data Matrix a = ZeroM | ScalarM a |
  QuadM (Matrix a, Matrix a, Matrix a, Matrix a)
    deriving (Show, Eq)
&lt;/pre&gt;

&lt;p&gt;As described above, a quadtree matrix is either a zero matrix, a scalar matrix, or a quadtree node of four quadtree matrices.&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4142216997767480230?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4142216997767480230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4142216997767480230' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4142216997767480230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4142216997767480230'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/12/quadtree-matrices.html' title='Quadtree Matrices'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4077232952750441112</id><published>2009-12-19T09:00:00.000-05:00</published><updated>2009-12-19T09:00:04.609-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>The Power of Metaphor</title><content type='html'>&lt;p&gt;Today's recess break (if I can use my own metaphor for my blog) is a TED talk that was just released about metaphors:&lt;/p&gt;

&lt;object width="446" height="326"&gt;&lt;param name="movie" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;param name="bgColor" value="#ffffff"&gt;&lt;/param&gt; &lt;param name="flashvars" value="vu=http://video.ted.com/talks/dynamic/JamesGeary_2009G-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/JamesGeary-2009G.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=716&amp;introDuration=16500&amp;adDuration=4000&amp;postAdDuration=2000&amp;adKeys=talk=james_geary_metaphorically_speaking;year=2009;theme=the_creative_spark;theme=how_the_mind_works;theme=art_unusual;theme=words_about_words;event=TEDGlobal+2009;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" /&gt;&lt;embed src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" pluginspace="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" bgColor="#ffffff" width="446" height="326" allowFullScreen="true" flashvars="vu=http://video.ted.com/talks/dynamic/JamesGeary_2009G-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/JamesGeary-2009G.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=716&amp;introDuration=16500&amp;adDuration=4000&amp;postAdDuration=2000&amp;adKeys=talk=james_geary_metaphorically_speaking;year=2009;theme=the_creative_spark;theme=how_the_mind_works;theme=art_unusual;theme=words_about_words;event=TEDGlobal+2009;"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;Just about &lt;em&gt;every&lt;/em&gt; TED video is worth watching, but this one has some implications for Extreme Programming and good programming in general.  One of the XP practices is picking a good metaphor for your code.  In this TED talk, James Geary revels in the power of metaphor.&lt;/p&gt;

&lt;p&gt;One observation that shook me up: we have a hard time denying a metaphor even if it's literally false.  Geary gives this as an example: "Some jobs are jails."  It's &lt;em&gt;literally&lt;/em&gt; false, but for some of us it's very metaphorically true.  To recognize and say that it's literally false takes some time and effort.  (More time and effort than it takes to say that "Some squares are round" is false.)&lt;/p&gt;

&lt;p&gt;Now I don't think we have to worry about literal-versus-metaphorical truthiness in our programming, but this shows how very important and powerful metaphors are.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4077232952750441112?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4077232952750441112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4077232952750441112' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4077232952750441112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4077232952750441112'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/12/power-of-metaphor.html' title='The Power of Metaphor'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8681721341034645238</id><published>2009-12-18T12:45:00.003-05:00</published><updated>2009-12-18T13:11:32.402-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='system administration'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Installing Passenger on My MacBook</title><content type='html'>&lt;p&gt;I'd like to play around with &lt;a href="http://www.modrails.com/"&gt;Passenger&lt;/a&gt; on my MacBook, running Snow Leopard and MacPorts.  Passenger is an Apache module for Ruby on Rails apps; it's supposed to make deploying a breeze.  But I can't get it installed.&lt;/p&gt;

&lt;h3&gt;The Problem&lt;/h3&gt;

&lt;p&gt;When I install the Passenger module for Apache, I get this output:&lt;/p&gt;

&lt;pre&gt;
Checking for required software...

 * GNU C++ compiler... found at /usr/bin/g++
 * Ruby development headers... found
 * OpenSSL support for Ruby... found
 * RubyGems... found
 * Rake... found at /opt/local/bin/rake
 * rack... found
 * Apache 2... found at /usr/sbin/httpd
 * Apache 2 development headers... found at /usr/sbin/apxs
 * Apache Portable Runtime (APR) development headers... found at /usr/bin/apr-1-config
 * Apache Portable Runtime Utility (APU) development headers... found at /usr/bin/apu-1-config

--------------------------------------------
Compiling and installing Apache 2 module...
cd /opt/local/lib/ruby/gems/1.8/gems/passenger-2.2.8
/opt/local/bin/ruby -S /opt/local/bin/rake clean apache2
# /opt/local/bin/ruby -S /opt/local/bin/rake clean apache2
(in /opt/local/lib/ruby/gems/1.8/gems/passenger-2.2.8)
rm -rf ext/apache2/libboost_oxt.a ext/apache2/libboost_oxt
rm -rf ext/apache2/libpassenger_common.a ext/apache2/ApplicationPoolServerExecutable ext/apache2/libpassenger_common
rm -rf ext/apache2/Configuration.o ext/apache2/Bucket.o ext/apache2/Hooks.o ext/apache2/mod_passenger.o ext/apache2/mod_passenger.so
rm -rf ext/nginx/libboost_oxt.a ext/nginx/libboost_oxt
rm -rf ext/nginx/libpassenger_common.a ext/nginx/libpassenger_common
rm -rf ext/nginx/HelperServer
rm -rf test/libboost_oxt.a test/libboost_oxt
rm -rf test/libpassenger_common.a test/ApplicationPoolServerExecutable test/libpassenger_common
rm -rf test/oxt/oxt_test_main test/oxt/*.o test/CxxTests test/*.o
rm -r pkg
cd ext/phusion_passenger &amp;&amp; make clean
rm -f ext/phusion_passenger/Makefile
mkdir -p ext/apache2/libpassenger_common
g++ -Iext -Iext/common -fPIC -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS -o ext/apache2/libpassenger_common/Utils.o -c ext/common/Utils.cpp
In file included from ext/boost/config/no_tr1/utility.hpp:21,
                 from ext/boost/config/select_stdlib_config.hpp:20,
                 from ext/boost/config.hpp:40,
                 from ext/boost/thread/detail/platform.hpp:14,
                 from ext/boost/thread/tss.hpp:9,
                 from ext/oxt/system_calls.hpp:28,
                 from ext/common/Utils.cpp:26:
/usr/include/c++/4.2.1/utility:65:28: error: bits/c++config.h: No such file or directory
In file included from /usr/include/c++/4.2.1/bits/stl_algobase.h:70,
                 from /usr/include/c++/4.2.1/memory:53,
                 from ext/boost/shared_ptr.hpp:23,
                 from ext/boost/thread/pthread/tss.hpp:10,
                 from ext/boost/thread/tss.hpp:13,
                 from ext/oxt/system_calls.hpp:28,
                 from ext/common/Utils.cpp:26:
/usr/include/c++/4.2.1/iosfwd:45:29: error: bits/c++locale.h: No such file or directory
/usr/include/c++/4.2.1/iosfwd:46:25: error: bits/c++io.h: No such file or directory
In file included from /usr/include/c++/4.2.1/memory:54,
                 from ext/boost/shared_ptr.hpp:23,
                 from ext/boost/thread/pthread/tss.hpp:10,
                 from ext/boost/thread/tss.hpp:13,
                 from ext/oxt/system_calls.hpp:28,
                 from ext/common/Utils.cpp:26:
/usr/include/c++/4.2.1/bits/allocator.h:53:31: error: bits/c++allocator.h: No such file or directory
In file included from /usr/include/c++/4.2.1/bits/basic_string.h:46,
                 from /usr/include/c++/4.2.1/string:54,
                 from ext/common/CachedFileStat.hpp:35,
                 from ext/common/Utils.cpp:34:
/usr/include/c++/4.2.1/ext/atomicity.h:39:23: error: bits/gthr.h: No such file or directory
/usr/include/c++/4.2.1/ext/atomicity.h:40:30: error: bits/atomic_word.h: No such file or directory
In file included from /usr/include/c++/4.2.1/bits/basic_ios.h:44,
                 from /usr/include/c++/4.2.1/ios:50,
                 from /usr/include/c++/4.2.1/ostream:45,
                 from /usr/include/c++/4.2.1/iterator:70,
                 from ext/boost/next_prior.hpp:15,
                 from ext/boost/utility.hpp:16,
                 from ext/boost/thread/pthread/thread.hpp:12,
                 from ext/boost/thread/thread.hpp:17,
                 from ext/boost/thread.hpp:12,
                 from ext/common/SystemTime.h:28,
                 from ext/common/CachedFileStat.hpp:39,
                 from ext/common/Utils.cpp:34:
/usr/include/c++/4.2.1/bits/locale_facets.h:47:30: error: bits/ctype_base.h: No such file or directory
/usr/include/c++/4.2.1/bits/locale_facets.h:1533:31: error: bits/ctype_inline.h: No such file or directory
/usr/include/c++/4.2.1/bits/locale_facets.h:3040:33: error: bits/time_members.h: No such file or directory
/usr/include/c++/4.2.1/bits/locale_facets.h:4599:37: error: bits/messages_members.h: No such file or directory
In file included from /usr/include/c++/4.2.1/utility:66,
                 from ext/boost/config/no_tr1/utility.hpp:21,
                 from ext/boost/config/select_stdlib_config.hpp:20,
                 from ext/boost/config.hpp:40,
                 from ext/boost/thread/detail/platform.hpp:14,
                 from ext/boost/thread/tss.hpp:9,
                 from ext/oxt/system_calls.hpp:28,
                 from ext/common/Utils.cpp:26:
/usr/include/c++/4.2.1/bits/stl_relops.h:74: error: expected constructor, destructor, or type conversion before ‘(’ token
In file included from /usr/include/c++/4.2.1/new:45,
                 from /usr/include/c++/4.2.1/bits/stl_construct.h:65,
                 from /usr/include/c++/4.2.1/memory:55,
                 from ext/boost/shared_ptr.hpp:23,
                 from ext/boost/thread/pthread/tss.hpp:10,
                 from ext/boost/thread/tss.hpp:13,
                 from ext/oxt/system_calls.hpp:28,
                 from ext/common/Utils.cpp:26:
/usr/include/c++/4.2.1/exception:40: error: expected declaration before end of line
lipo: can't figure out the architecture type of: /var/tmp//ccPAGdXv.out
rake aborted!
Command failed with status (1): [g++ -Iext -Iext/common -fPIC -DDARWIN -DSI...]
/opt/local/lib/ruby/gems/1.8/gems/passenger-2.2.8/Rakefile:172:in `define_common_library_task'
(See full trace by running task with --trace)

--------------------------------------------

It looks like something went wrong

Please read our Users guide for troubleshooting tips:

   /opt/local/lib/ruby/gems/1.8/gems/passenger-2.2.8/doc/Users guide Apache.html

If that doesn't help, please use our support facilities at:

   http://www.modrails.com/

We'll do our best to help you.
&lt;/pre&gt;

&lt;p&gt;I'm using the defaults from Apple except for Ruby and rake; they come from MacPorts.  The error messages seems to be a problem with the system g++.&lt;p&gt;

&lt;h3&gt;They're &lt;em&gt;Not&lt;/em&gt; Missing&lt;/h3&gt;

&lt;p&gt;For the record, the "missing" headers files are &lt;em&gt;not&lt;/em&gt; missing:&lt;/p&gt;

&lt;pre&gt;
&lt;strong&gt;$ locate bits/c++config.h&lt;/strong&gt;
/Developer/SDKs/MacOSX10.5.sdk/usr/include/c++/4.0.0/i686-apple-darwin9/bits/c++config.h
/Developer/SDKs/MacOSX10.5.sdk/usr/include/c++/4.0.0/powerpc-apple-darwin9/bits/c++config.h
/Developer/SDKs/MacOSX10.5.sdk/usr/include/c++/4.0.0/powerpc64-apple-darwin9/bits/c++config.h
/Developer/SDKs/MacOSX10.5.sdk/usr/include/c++/4.0.0/x86_64-apple-darwin9/bits/c++config.h
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.0.0/i686-apple-darwin10/bits/c++config.h
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.0.0/powerpc-apple-darwin10/bits/c++config.h
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.0.0/x86_64-apple-darwin10/bits/c++config.h
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/i686-apple-darwin10/bits/c++config.h
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/powerpc-apple-darwin10/bits/c++config.h
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/x86_64-apple-darwin10/bits/c++config.h
/opt/local/include/gcc43/c++/x86_64-apple-darwin10/bits/c++config.h
/opt/local/var/macports/software/gcc43/4.3.4_0/opt/local/include/gcc43/c++/x86_64-apple-darwin10/bits/c++config.h
/usr/include/c++/4.0.0/i686-apple-darwin10/bits/c++config.h
/usr/include/c++/4.0.0/powerpc-apple-darwin10/bits/c++config.h
/usr/include/c++/4.0.0/x86_64-apple-darwin10/bits/c++config.h
/usr/include/c++/4.2.1/i686-apple-darwin10/bits/c++config.h
/usr/include/c++/4.2.1/powerpc-apple-darwin10/bits/c++config.h
/usr/include/c++/4.2.1/x86_64-apple-darwin10/bits/c++config.h
/usr/local/nacl/googleclient/native_client/tools_bin/mac/sdk/nacl-sdk/nacl/include/c++/4.2.2/nacl/bits/c++config.h
&lt;/pre&gt;

&lt;p&gt;gcc might not be configured to use those directories, though (which does qualify as missing).  When I did a Google search for the error message, I get references to a "boost" library, but most of the hits are in a foreign language and seem to have &lt;em&gt;nothing&lt;/em&gt; to do with Passenger.&lt;/p&gt;

&lt;h3&gt;Try a Different gcc?&lt;/h3&gt;

&lt;p&gt;If MacPorts is good for Ruby and rake, why not gcc?  First, gcc-4.2 doesn't install on Snow Leopard.&lt;/p&gt;

&lt;p&gt;Second, gcc-4.3 does install, but results in this error message:&lt;/p&gt;

&lt;pre&gt;
mkdir -p ext/apache2/libpassenger_common
g++ -Iext -Iext/common -fPIC -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS -o ext/apache2/libpassenger_common/Utils.o -c ext/common/Utils.cpp
cc1plus: error: unrecognized command line option "-arch"
cc1plus: error: unrecognized command line option "-arch"
cc1plus: error: unrecognized command line option "-arch"
cc1plus: error: unrecognized command line option "-arch"
&lt;/pre&gt;

&lt;p&gt;This might just need a tweak of the Passenger rakefile.&lt;/p&gt;

&lt;p&gt;Third, I tried LLVM gcc-4.2:&lt;/p&gt;

&lt;pre&gt;
g++ ext/common/ApplicationPoolServerExecutable.cpp -o ext/apache2/ApplicationPoolServerExecutable -Iext -Iext/common  -fPIC -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS ext/apache2/libpassenger_common.a ext/apache2/libboost_oxt.a  -lpthread 
ld: warning: in /usr/lib/crt1.10.5.o, missing required architecture ppc64 in file
ld: warning: in /usr/lib/libpthread.dylib, missing required architecture ppc64 in file
ld: warning: in /Developer/usr/llvm-gcc-4.2/lib/gcc/powerpc-apple-darwin10/4.2.1/libstdc++.dylib, missing required architecture ppc64 in file
ld: warning: in /Developer/usr/llvm-gcc-4.2/lib/gcc/powerpc-apple-darwin10/4.2.1/libgcc.a, file is not of required architecture
ld: warning: in /usr/lib/libSystemStubs.a, missing required architecture ppc64 in file
ld: warning: in /usr/lib/libSystem.dylib, missing required architecture ppc64 in file
Undefined symbols for architecture ppc64:
  # deleted 6853 lines of error messages
&lt;/pre&gt;

&lt;p&gt;No, that's not a typo.  Six-thousand eight-hundred fifty-three lines of error messages!  Awesome.  I mean, I didn't expect it to work, but... wow.&lt;/p&gt;

&lt;h3&gt;Things I'm Left Trying...&lt;/h3&gt;

&lt;p&gt;As I write this, I'm compiling the boost library with MacPorts.  I don't think this will help with the Apple-installed gcc, and boost wasn't a problem for any of the MacPort-installed compilers, so I don't think this will do me any good.  &lt;strong&gt;Update:&lt;/strong&gt; it didn't help.&lt;/p&gt;

&lt;p&gt;The only other thing I can think to try is to get rid of the &lt;code&gt;-arch&lt;/code&gt; option in the compilation command.&lt;/p&gt;

&lt;p&gt;I'll post any fixes or further frustrations as they arise.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8681721341034645238?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8681721341034645238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8681721341034645238' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8681721341034645238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8681721341034645238'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/12/installing-passenger-on-my-macbook.html' title='Installing Passenger on My MacBook'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-806626656895845247</id><published>2009-12-16T14:50:00.001-05:00</published><updated>2009-12-16T14:50:51.032-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='quadtree matrices'/><title type='text'>Going Back to My Dissertation</title><content type='html'>&lt;p&gt;My dissertation was on quadtree matrices.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://en.wikipedia.org/wiki/Quadtree"&gt;quadtree entry&lt;/a&gt; in the Wikipedia provides maybe one sentence about "quadtree matrices".  And it's probably my fault there isn't more since I'm one of about a dozen people in the world who has published papers on quadtree matrices.  So I'm going to spend a blog entry or two introducing the topic.  (Maybe I can turn this introduction into a Wikipedia article.)&lt;/p&gt;

&lt;p&gt;I'm motivated to do this now because I've returned to the Haskell code that started my quadtree-matrix work.  I'm coming across issues as I'm relearning and perfecting my Haskell skills, and discussing problems like these on my blog has helped me in the past.&lt;/p&gt;

&lt;p&gt;So, hopefully, I'll have a series of posts about my adventures in Haskell, implementing quadtree matrices and some interesting algorithms.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-806626656895845247?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/806626656895845247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=806626656895845247' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/806626656895845247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/806626656895845247'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/12/going-back-to-my-dissertation.html' title='Going Back to My Dissertation'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-751165263393219503</id><published>2009-07-08T15:50:00.002-04:00</published><updated>2009-07-08T16:04:12.833-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Testing Redirection and Rewrite Rules with RSpec</title><content type='html'>&lt;p&gt;One the websites that I maintain has quite a few interesting Redirect and RewriteRules in its Apache configuration.  Up until yesterday, I was testing them with Selenium; today I'm testing with RSpec.&lt;/p&gt;

&lt;p&gt;The website is for the &lt;a href="http://cs.calvin.edu/"&gt;Computer Science department at Calvin&lt;/a&gt;.  Most of it is a &lt;a href="http://www.github.com/jdfrens/calvincs/"&gt;Rails app&lt;/a&gt; for a CMS.  However, there were portions of the old site that I wanted to leave in the hands of my former colleagues; there were other paths into the site that needed to be redirected.&lt;/p&gt;

&lt;h3&gt;Selenium, Not Such a Good Idea for This Problem&lt;/h3&gt;

&lt;p&gt;I really like &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; for writing website tests in a browser, and I've seen how useful it can be for developing Rails apps.  I applied it to this rewrite-and-redirect problem, and it was more than a bit of overkill.  In my role as "website developer", I just needed to make sure the redirects were in place.  With Selenium, though, I found myself testing other features, like content on pages or in directories that I wasn't really in charge of.&lt;/p&gt;

&lt;p&gt;The Selenium tests also ran slow since it used Firefox itself to access the website.&lt;/p&gt;

&lt;p&gt;I also found the tests hard to maintain.  This is mostly on me because I saved and edited them in an HTML format.  It would have been better to use Ruby.  But if I was going to rewrite the tests in a format that was easier to use, why not also go for something faster and more targeted?&lt;/p&gt;

&lt;h3&gt;Ruby and RSpec&lt;/h3&gt;

&lt;p&gt;Ruby has libraries to access URLs through HTTP... &lt;strong&gt;core&lt;/strong&gt; libraries.  I can write expectations in RSpec.  I can write expectations about the HTTP responses.&lt;/p&gt;

&lt;p&gt;This was all theoretically possible until I came across &lt;a href="http://www.viget.com/extend/test-drive-mod-rewrite-rules-with-testunit/"&gt;"Test Drive mod_rewrite Rules with Test::Unit"&lt;/a&gt; by Patrick Reagan.  Someone had done it already (as I figured) with Test::Unit.  Instead of using Patrick's solution wholesale, I decided to tailor it more towards my needs, especially towards RSpec.&lt;/p&gt;

&lt;h3&gt;My mod_rewrite Expectations with RSpec&lt;/h3&gt;

&lt;p&gt;Here's what one of my expectations looks like:&lt;/p&gt;

&lt;pre&gt;
it "should redirect curriculum pages" do
  get("/curriculum/bcs.php").should redirect_to("/p/bcs")
  get("/curriculum/bacs.php").should redirect_to("/p/bacs")
  get("/curriculum/bais.php").should redirect_to("/p/bais")
  get("/curriculum/bada.php").should redirect_to("/p/bada")
end
&lt;/pre&gt;

&lt;p&gt;We had a few pages for the the different computing degrees at Calvin College: an ABET-accredited Bachelor's of Computer Science and plain BAs in Computer Science, Information Systems, and "Digital Arts".  We &lt;em&gt;definitely&lt;/em&gt; wanted all links to the old pages go to the new.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;get(path)&lt;/code&gt; is my method:&lt;/p&gt;

&lt;pre&gt;
def get(url)
  RedirectCheck.new(ResourcePath.new("http://cs.calvin.edu" + url))
end
&lt;/pre&gt;

&lt;p&gt;Yes, I've hard-coded the server in this test.  It keeps the rest of the code simpler, and it solves the problem I have now.&lt;/p&gt;

&lt;p&gt;The two classes used here are based on &lt;a href="http://gist.github.com/69583"&gt;classes of the same name&lt;/a&gt; by Patrick.  You can see my versions in &lt;a href="http://github.com/jdfrens/calvincs/tree/d5e5cc67dad928bccd015f13e1b33f4a438ade96/deployment/support"&gt;the GitHub repository&lt;/a&gt;.  I mostly just simplified the code for my purposes.&lt;/p&gt;

&lt;p&gt;The really important class is &lt;code&gt;RedirectCheck&lt;/code&gt;.  It accesses the URL, saves the response, and then parses it for queries like &lt;code&gt;success?&lt;/code&gt; and &lt;code&gt;redirect?&lt;/code&gt; and &lt;code&gt; redirected_path&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;success?&lt;/code&gt; allowed me to write expectations like this without any extra work:&lt;/p&gt;

&lt;pre&gt;
it "should have a books activity" do
  get("/activities/books/").should be_success
  get("/a/books/").should be_success
end
&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;redirect?&lt;/code&gt; and &lt;code&gt;redirect_path&lt;/code&gt; make the &lt;code&gt;redirect_to(path)&lt;/code&gt; matcher easy:&lt;/p&gt;
  
&lt;pre&gt;
Spec::Matchers.define :redirect_to do |redirection|
  match do |redirect_check|
    redirect_check.redirected?.should == true
    redirect_check.redirected_path.should == redirection
  end
end
&lt;/pre&gt;

&lt;p&gt;For some reason, &lt;code&gt;redirect_check.should be_redirected&lt;/code&gt; triggers an undefined error for &lt;code&gt;be_redirected&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;redirection&lt;/code&gt; is the redirection path (i.e., the expected path).  &lt;code&gt;redirect_check&lt;/code&gt; is a &lt;code&gt;RedirectCheck&lt;/code&gt; object created by &lt;code&gt;get(path)&lt;/code&gt;.&lt;/p&gt;


&lt;h3&gt;Performance&lt;/h3&gt;

&lt;p&gt;It takes about 3 seconds to run 15 examples, so it's not the speediest RSpec suite around (by a long shot).  But these aren't tests to be run often.  Plus, the original Selenium tests &lt;em&gt;never&lt;/em&gt; ran that fast!&lt;/p&gt;

&lt;p&gt;So, given the problem I was trying to solve, I really like this solution.  It'll be easy to add more expectations if I need to.  It's really easy to run them, too.  I'll save Selenium for a problem that &lt;em&gt;really&lt;/em&gt; requires it!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-751165263393219503?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/751165263393219503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=751165263393219503' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/751165263393219503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/751165263393219503'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/07/testing-redirection-and-rewrite-rules.html' title='Testing Redirection and Rewrite Rules with RSpec'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2625793597423298051</id><published>2009-07-06T12:52:00.001-04:00</published><updated>2009-07-06T12:53:52.479-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='howto'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Converting from Test::Unit to RSpec in a Rails App</title><content type='html'>&lt;p&gt;I'm going to write my process turning the Test::Unit tests into RSpec examples for &lt;a href="http://github.com/jdfrens/yags"&gt;another Rails app&lt;/a&gt; in realtime.  The app is called "YAGS" (Yet Another Genetics Simulatr), for simulating the genetics of fruit flies for a college-level biology course.  I &lt;a href="http://github.com/jdfrens/calvincs"&gt;did this transformation once before&lt;/a&gt;; this app is a little bit more than a CMS for my former CS department.&lt;/p&gt;

&lt;p&gt;My post for the department CMS transformation was organized topically.  I'm organizing this one chronologically.&lt;/p&gt;


&lt;h2&gt;Measure the State of the App&lt;/h2&gt;

&lt;pre&gt;
# unit tests
124 tests, 758 assertions, 0 failures, 0 errors
Test suite finished: 5.091451 seconds
# functional tests
164 tests, 1311 assertions, 0 failures, 0 errors
Test suite finished: 6.700129 seconds
# integration tests?! we don't need no stinkin' integration tests!
&lt;/pre&gt;



&lt;h2&gt;Install RSpec and RSpec-Rails in the App&lt;/h2&gt;

&lt;p&gt;While I'm at it, I think I'll also get Cucumber set up.  (The last time in my "state of the app" is a lie; everyone needs integration tests!)&lt;/p&gt;

&lt;p&gt;I drop these into my &lt;code&gt;config/environments/test.rb&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;
config.gem "rspec", :lib =&gt; false, :version =&gt; "&gt;= 1.2.7"
config.gem "rspec-rails", :lib =&gt; false, :version =&gt; "&gt;= 1.2.7"
config.gem "aslakhellesoy-cucumber", :lib =&gt; "cucumber", :version =&gt; "&gt;= 0.3.11"
config.gem 'webrat'
&lt;/pre&gt;

&lt;p&gt;These may be useful for a limited time only (especially getting cucumber from GitHub).  I run these shell commands:&lt;/p&gt;

&lt;pre&gt;
# I don't bother to install since I know they're installed
rake gems:unpack RAILS_ENV=test
rake gems:unpack:dependencies RAILS_ENV=test
./script/generate rspec
./script/generate cucumber
&lt;/pre&gt;

&lt;blockquote&gt;
  &lt;p&gt;Question for Rails experts: with the &lt;code&gt;gems&lt;/code&gt; tasks (like &lt;code&gt;install&lt;/code&gt; and &lt;code&gt;unpack&lt;/code&gt;), is it necessary or even desirable to add the gems to version control?  Can't you have your deploy script do the installing and unpacking?  I'd really appreciate feedback on this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I run the &lt;code&gt;spec&lt;/code&gt; and &lt;code&gt;features&lt;/code&gt; tasks, and they both run without errors.  Cucumber at least reports "0 scenarios, 0 steps"; RSpec is mute.&lt;/p&gt;



&lt;h2&gt;Copying Tests Over&lt;/h2&gt;

&lt;pre&gt;
mkdir spec/models
mkdir spec/controllers
mkdir spec/views
mkdir spec/fixtures
cp test/unit/*.rb spec/models/
cp test/functional/*.rb spec/controllers/
cp test/fixtures/*.yml spec/fixtures/
&lt;/pre&gt;

&lt;p&gt;I have to make the directories because I haven't generated any examples for RSpec directly.  When I finish with these steps, I discover why the &lt;code&gt;spec&lt;/code&gt; task didn't seem to do anything: it didn't find any specs because the filenames of specs end in &lt;code&gt;_spec.rb&lt;/code&gt;, not &lt;code&gt;_test.rb&lt;/code&gt;.  I wish I could give a command-line solution for this, but I haven't been able to find a way to get &lt;a href="http://linux.maruhn.com/sec/mmv.htm"&gt;&lt;code&gt;mmv&lt;/code&gt;&lt;/a&gt; (multiple &lt;code&gt;mv&lt;/code&gt;) installed on my Mac.  Coincidentally, I just discovered &lt;a href="http://www.mrrsoftware.com/MRRSoftware/NameChanger.html"&gt;NameChanger&lt;/a&gt; today, and it does a very nice job at renaming the files.&lt;/p&gt;

&lt;p&gt;I suppose this might work:&lt;/p&gt;

&lt;pre&gt;
# run in spec/models, spec/controllers
for i in *_test.rb; do
  mv $i ${i%%_test.rb}_spec.rb
done
&lt;/pre&gt;

&lt;p&gt;(After I finished the whole Test::Unit-to-RSpec transformation, I discovered that &lt;code&gt;mmv&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; available in MacPorts!  The name of the packge is &lt;code&gt;mmv&lt;/code&gt;.  I'm too lazy now to figure out what the right &lt;code&gt;mmv&lt;/code&gt; command would be, but it's not to hard to figure out.)


&lt;h2&gt;Can't Find Test Helpers&lt;/h2&gt;

&lt;pre&gt;
no such file to load -- ./spec/controllers/../test_helper (LoadError)
&lt;/pre&gt;

&lt;p&gt;That's because they're spec helpers now!&lt;/p&gt;

&lt;p&gt;I use RubyMine's "Search &amp;gt; Replace in Path..." to replace the &lt;code&gt;test_helper&lt;/code&gt; requires with &lt;code&gt;spec_helper&lt;/code&gt; requires.&lt;/p&gt;

&lt;p&gt;I know the next problem: helpers that I haven't copied over to &lt;code&gt;spec_helper&lt;/code&gt;!&lt;/p&gt;


&lt;h2&gt;nokogiri Gem Acting Up&lt;/h2&gt;

&lt;p&gt;Two minutes later... I'm wrong, of course!  I'm &lt;em&gt;not&lt;/em&gt; having troubles with the helper methods yet.  I'm having troubles with nokogiri and/or webrat.  The basic error message is this:&lt;/p&gt;

&lt;pre&gt;
no such file to load -- nokogiri/nokogiri
&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;spec&lt;/code&gt; task also spits out a lengthy stack trace and concludes that webrat isn't installed.  Well, newsflash! webrat is installed, and so is nokogiri.  But there isn't a &lt;code&gt;lib/nokogiri/nokogiri.rb&lt;/code&gt; file anywhere that makes sense out of the error message.  Even more frustrating, my other Rails app isn't having a problem with webrat and nokogiri&lt;/p&gt;

&lt;p&gt;There &lt;em&gt;is&lt;/em&gt;, however, a difference between the two apps: I do &lt;em&gt;not&lt;/em&gt; have webrat and nokogiri in &lt;code&gt;vendor/gems&lt;/code&gt; in the CMS app.  They have been unpacked in the YAGS app.&lt;p&gt;
  
&lt;pre&gt;
rm -rf vendor/gems/webrat-0.4.4
rm -rf vendor/gems/nokogiri-1.3.2
&lt;/pre&gt;

&lt;p&gt;Problem solved.  I won't say I'm happy with the solution since it begs the question why it works, but webrat (and Cucumber) have been in enough flux lately that I don't worry if I have to do something out of the ordinary to get them to work for a while.  As far as "out of the ordinary" goes, deleting the gems from &lt;code&gt;vendor/gems&lt;/code&gt; isn't going to cause me to lose any sleep.&lt;/p&gt;

&lt;p&gt;And I get my predicted error: methods defined in &lt;code&gt;test_helper.rb&lt;/code&gt; that aren't in &lt;code&gt;spec_helper.rb&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;Adding to Spec helpers&lt;/h2&gt;

&lt;p&gt;I start moving methods over.  One bad thing we did in &lt;code&gt;test_helper.rb&lt;/code&gt; was to define the helper methods at the top level.  So I'm putting them into modules, and then using &lt;code&gt;config.extend&lt;/code&gt; and &lt;code&gt;config.include&lt;/code&gt; for class and instance methods, respectively.  (I believe I learned about this from the RSpec book.  There should be documentation online for this as well.)&lt;/p&gt;

&lt;p&gt;One thing I notice is that I'm not requiring webrat in &lt;code&gt;spec_helper.rb&lt;/code&gt;, and I did require it explicitly in my CMS app.  Requiring in the YAGS app doesn't revert me to the &lt;code&gt;nokogiri/nokogiri&lt;/code&gt; error from before, so I'll leave the require in.&lt;/p&gt;

&lt;p&gt;However, I get one method moved over, and suddenly I'm getting a complaint about shoulda's &lt;code&gt;should_have_many&lt;/code&gt;.
  
  
  
&lt;h2&gt;Shoulda Gem with RSpec and Test::Unit&lt;/h2&gt;

&lt;pre&gt;undefined method `should_have_many' for UserTest:Class&lt;/pre&gt;

&lt;p&gt;After fighting with this for a while, here's what I've figured out.  The excellent &lt;a href="http://github.com/thoughtbot/shoulda"&gt;shoulda gem&lt;/a&gt; &lt;em&gt;is&lt;/em&gt; being loaded; the &lt;code&gt;context&lt;/code&gt; method works just fine.  So it's not a load path problem or other directory issue.  Poking around in the code, &lt;code&gt;shoulda.rb&lt;/code&gt; itself asks this question: &lt;code&gt;defined? Spec&lt;/code&gt; and loads different libraries depending on what you pick.  That is, you can have shoulda code for RSpec &lt;em&gt;or&lt;/em&gt; Test::Unit, but not both!&lt;/p&gt;

&lt;p&gt;Keep in mind that while I'm converting to RSpec, the tests themselves are still very much in a Test::Unit form.  RSpec is supposed to handle them without too many problems.&lt;/p&gt;

&lt;p&gt;Perhaps there are some games I could play with requiring files myself, but I'm not sure how compatible the RSpec and Test::Unit versions are, and I figure: why not start the true coversion to RSpec now?  So I end up moving the &lt;code&gt;should_have_many&lt;/code&gt; assertion to a new &lt;code&gt;describe&lt;/code&gt; block:&lt;/p&gt;

&lt;pre&gt;
describe User do
  it { should have_many :vials }
end
&lt;/pre&gt;

&lt;p&gt;I also drop the underscore between &lt;code&gt;should&lt;/code&gt; and &lt;code&gt;have_many&lt;/code&gt;.  (I'm fudging a bit on the chronology here because iI discovered this problem later.)  I'm actually not sure if the &lt;code&gt;describe&lt;/code&gt; block is completely necessary after this change, but since I want to move in that direction anyway, I'm going to keep going in that direction.&lt;/p&gt;

&lt;p&gt;I keep this in the same file as the Test::Unit test case.  Works fine, and so I go on to fix all of these shoulda problems.&lt;/p&gt;


&lt;h2&gt;&lt;code&gt;should&lt;/code&gt; Is a Reserved Word&lt;/h2&gt;

&lt;p&gt;Well, not really, of course.  Actually, the problem is that both shoulda and RSpec have it as a "reserved word", but the meaning is different.  (I suppose this might be a definition of a Object- or Kernel-level method: a keyword whose meaning can be changed.  It &lt;em&gt;should&lt;/em&gt; (pardon the pun) be treated as a keyword, but it's meaning can be changed due to which class it's added to.)&lt;/p&gt;

&lt;p&gt;All the old shoulda tests that use &lt;code&gt;should "X"&lt;/code&gt; have to be turned into &lt;code&gt;it "should X"&lt;/code&gt;.  Time for Replace in Path again!&lt;/p&gt;

&lt;p&gt;There are only a few to change, and now finally the specs all run and 186 out of 288 fail!  It appears I have more methods to move to &lt;code&gt;spec_helper&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;Smelly Code&lt;/h2&gt;

&lt;p&gt;Along the way, I discover that some of the helper methods are quite stinky.  Or some of the tests that they "inspire" are quite stinky.  The biggest stink comes from black-box testing the associations and their dependencies.  That is, for example, we had tests that would use the fixture data to make sure the right vial had the right flies in it.  And if we deleted that vial, the right flies would also go.  shoulda and RSpec make this much easier:&lt;/p&gt;

&lt;pre&gt;
it { should have_many(:flies).dependent(:destroy) }
&lt;/pre&gt;

&lt;p&gt;It reads short and sweet, and it doesn't involve any data checking.&lt;/p&gt;


&lt;h2&gt;Finishing Is Only the Beginning&lt;/h2&gt;

&lt;p&gt;How poetic.  Gag!&lt;/p&gt;

&lt;pre&gt;
287 examples, 0 failures, 287 passed
Finished in 12.497872 seconds
&lt;/pre&gt;

&lt;p&gt;If you look at where I started with my tests, there were 288 unit and functional tests.  I've added some new ones, and deleted old ones, so 287 examples sounds pretty good to me.&lt;/p&gt;

&lt;p&gt;I'm not finished with the conversion, of course.  I've discovered quite a few unit tests for models that still have &lt;em&gt;only&lt;/em&gt; their default "test true" stub!  Also I plan to separate the controller and view examples; this I typically do when needed though.&lt;/p&gt;

&lt;p&gt;I need one set of view examples soon: I "ignored" a &lt;code&gt;assert_standard_layout&lt;/code&gt; helper method.  This method did a lot of looking at the HTML generated by the standard layout.  It gets called several times throughout the tests.  This was always overkill, but it seemed like a good idea to me to make sure that each action was using the standard layout and wasn't screwing it up.  RSpec allows one to separate out the rendering from the controlling, so for the RSpec examples, for the time being, I just wrote a version of the method that does nothing.  I need to write targeted view examples that will make the same assertions about the standard layout and then not worry about the standard layout anywhere else in the examples.&lt;/p&gt;



&lt;h2&gt;Biggest Mistake&lt;/h2&gt;

&lt;p&gt;Realistically, this isn't a huge mistake, but it was sloppy: I forgot to create a git branch for all of this work; I've been doing it all on &lt;code&gt;master&lt;/code&gt;!  Consequently, I've been afraid to make commits along the way since I try to keep the &lt;code&gt;master&lt;/code&gt; green on every commit (or merge).&lt;/p&gt;

&lt;p&gt;Worse yet, I realized this mistake somewhat early on, and did nothing about it.  I believe that there are ways to stash what you're working on, create a new branch, and use the stash on the new branch.  (I believe it's even &lt;code&gt;git-stash&lt;/code&gt; that let's you do this.)  Even if that didn't work, would it have been so terrible to revert all of my changes, create a new branch, and start over from scratch?  Even if I did that now, would it be &lt;em&gt;that&lt;/em&gt; much work?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2625793597423298051?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2625793597423298051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2625793597423298051' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2625793597423298051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2625793597423298051'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/07/converting-from-testunit-to-rspec-in.html' title='Converting from Test::Unit to RSpec in a Rails App'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4073410697523582818</id><published>2009-07-03T11:03:00.001-04:00</published><updated>2009-07-03T11:08:57.718-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sapir-whorf'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Empirical Evidence: Learn Haskell</title><content type='html'>&lt;p&gt;I read this morning an article by Lera Boroditsky, &lt;a href="http://edge.org/3rd_culture/boroditsky09/boroditsky09_index.html"&gt;"How Does Our Language Shape the Way We Think?"&lt;/a&gt;.  Very interesting read.&lt;/p&gt;

&lt;p&gt;I've often wondered if I should have become a linguist instead of a computer scientist (or mathematician).  One idea that's intrigued me is the &lt;a href="http://en.wikipedia.org/wiki/Sapir-Whorf_hypothesis"&gt;Sapir-Whorf hypothesis&lt;/a&gt;.  According to that Wikipedia article (as of today), the hypothesis is&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;the idea that the varying cultural concepts and categories inherent in different languages affect the cognitive classification of the experienced world in such a way that speakers of different languages think and behave differently because of it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Boroditsky's article suggests that there &lt;em&gt;is&lt;/em&gt; something to the Sapir-Whorf hypothesis.  The Wikipedia article (which I only scanned), seems to agree.  The lingering questions, though, are how does it work and to what degree does it apply?&lt;/p&gt;

&lt;p&gt;I've been interested in the hypothesis when teaching a Programming Languages course.  Students will often complain about having to learn Scheme, Haskell, or Prolog (when they've been raised on Java and C++).  The recursion in these languages is often a serious shift for the students (especially when other instructors tell them that &lt;em&gt;they&lt;/em&gt; don't get recursion).  Haskell has the extra "hassle" of a type system that's unlike type systems they've seen before.  And Prolog is completely declarative, and even I find the data flow tricky.&lt;/p&gt;

&lt;p&gt;Too often, if students talk about learning a new language, they're really looking to learn an &lt;em&gt;old&lt;/em&gt; language with a new syntax.  For the record, these are all pretty much the same language: Java, C++, C, PHP, Perl, C#, etc.  While learning a couple of these will certainly improve a resume, it won't really make you a better programmer, just better skilled.&lt;/p&gt;

&lt;p&gt;Scheme and Haskell made me think differently, especially Haskell.  I picked up a LISP book when I was in high school, and I actually understood most of it (without running any of the code).  Learning Scheme in grad school made me realize how deficient that LISP book was.  Haskell made me appreciate composing functions, type systems, and pattern matching.  Prolog got me into a declarative state of mind.&lt;/p&gt;

&lt;p&gt;It'll be interesting to see where languages like Ruby and Python take us.  I'd label both of these as "object-oriented languages with strong functional-programming influences".  Can programmers learn the FP features?  Will they embrace them?  Would learning Scheme or Haskell first help?  Hurt?&lt;/p&gt;

&lt;p&gt;Well, whatever you think about these larger issues, read Boroditsky's article.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4073410697523582818?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4073410697523582818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4073410697523582818' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4073410697523582818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4073410697523582818'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/07/empirical-evidence-learn-haskell.html' title='Empirical Evidence: Learn Haskell'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3108844310115027118</id><published>2009-07-01T09:44:00.003-04:00</published><updated>2009-07-01T10:22:55.320-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Upgrading Rails 1.2 to 2.3</title><content type='html'>&lt;p&gt;While I reel from the terrible error in my &lt;a href="http://jdfrens.blogspot.com/2009/06/anti-if-campaign.html"&gt;previous post&lt;/a&gt;, I thought I'd post about my recent experience updating a Rails app from version 1.2 to 2.3.  (BTW, the error is Andy's last name.  I'm still right about the anti-if campaign.)&lt;/p&gt;

&lt;p&gt;I had a real fun time upgrading a Rails app for my department's website (now &lt;a href="https://github.com/jdfrens/calvincs/tree"&gt;on GitHub&lt;/a&gt;), and by "real fun time" I mean "lots of pain and suffering".  More recently (like this past March) I discovered this &lt;a href="http://marklunds.com/articles/one/409"&gt;wonderful guide&lt;/a&gt; by Peter Marklund.  So when I went to upgrade a second app (also &lt;a href="https://github.com/jdfrens/yags/tree"&gt;on GitHub&lt;/a&gt;), I went through his process.&lt;/p&gt;

&lt;p&gt;Let me say this up front: I'm quite sure that Peter's instructions will work for you.  They're good instructions: they tell you the steps to take and the pitfalls to watch for.  Whatever they don't tell you, Rails will tell you.&lt;/p&gt;

&lt;p&gt;However, the process took me a couple days to complete.  Somehow I broke Rack.  Once I reached the step of running some rake tasks, I was told that &lt;code&gt;Rack::Request&lt;/code&gt; was an undefined constant.  Um... that's a Rails internal (sort of); I really don't think that's my responsibility!&lt;/p&gt;

&lt;p&gt;Long story short: I had my own &lt;code&gt;Rack&lt;/code&gt; model in the app!  That &lt;code&gt;Rack&lt;/code&gt; class was shadowing the &lt;a href="http://guides.rubyonrails.org/rails_on_rack.html"&gt;&lt;code&gt;Rack&lt;/code&gt; module that's now part of Rails&lt;/a&gt;.  Yesterday I spend 70 minutes refactoring my app to rename my &lt;code&gt;Rack&lt;/code&gt; (to &lt;code&gt;Shelf&lt;/code&gt;, thanks for asking), and it's working fine (at least according to the tests).&lt;/p&gt;

&lt;p&gt;Short story long: one of the keys in debugging this problem is that after being frustrated by the error for quite a while and trying to debug what was so terribly wrong with my load path, I decided to take smaller steps.  Instead of going from version 1.2 to 2.3, why not upgrade to 2.1 first?  That didn't work too well either, but I forget why now.  Since it didn't cost much at that point, I tried to upgrade to 2.2.  If that failed, I could try for 2.1 or even 2.0 for a smaller step; if it worked, then I wouldn't complain.  Fortunately, the upgrade to 2.2 went fine.&lt;/p&gt;

&lt;p&gt;I didn't immediately remember that Rack was added in 2.3, but that was a key insight when I finally realized the problem.  I believe the tipping point came when I did a full text search of the whole project in RubyMine.  Then all the references to the &lt;code&gt;Rack&lt;/code&gt; &lt;em&gt;model&lt;/em&gt; jumped out and screamed at me.&lt;/p&gt;

&lt;p&gt;This makes me wonder what would have happened if I had looked over the app before upgrading.  I had forgotten that the &lt;code&gt;Rack&lt;/code&gt; model even existed.  Would five minutes of scanning the models and controllers at the beginning have made this problem easier (even trivial) to debug?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3108844310115027118?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3108844310115027118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3108844310115027118' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3108844310115027118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3108844310115027118'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/07/upgrading-rails-12-to-23.html' title='Upgrading Rails 1.2 to 2.3'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-6444173699392463241</id><published>2009-06-27T13:04:00.000-04:00</published><updated>2009-06-27T14:37:00.844-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='programming style'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Anti-If Campaign</title><content type='html'>&lt;p&gt;A few days ago, I tweeted &lt;a href="http://twitter.com/jdfrens/status/2318312887"&gt;this&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Only reading the tagline on the homepage, this seems like a campaign I can get behind: &lt;a href="http://www.antiifcampaign.com/"&gt;http://www.antiifcampaign.com/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is actually a theme I've had in my head while teaching Programming Languages the last two years.  (I say "in my head" because I was always coy about this, presenting the issues rather than making a blanket statement: &lt;code&gt;if&lt;/code&gt;s are evil!)&lt;/p&gt;

&lt;p&gt;Andy Meneeley, a former student and friend of mine, responded:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;@jdfrens Sounds intriguing, but they only have one (trivial!) code example, then the rest of the site is just promo: a typical Agile smell.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The slam against agile ("Agile", really? capitalized?) was to get my hackles raised.  Well, raised they are!  I tried composing a Twitter reply, but 140 characters doesn't do justice to my hackles.&lt;p&gt;
  
&lt;h2&gt;Smackdown&lt;/h2&gt;
  
&lt;p&gt;Here's the thing: if you want a non-trivial example, if you want multiple examples, &lt;em&gt;look at any object-oriented program which uses polymorphism!&lt;/em&gt;  That's &lt;em&gt;not&lt;/em&gt; using an &lt;code&gt;if&lt;/code&gt;.  I'm beginning to re-think my choice of introductory programming language; maybe we should go back to Pascal so that students can appreciate OOP!&lt;/p&gt;

&lt;p&gt;Polymorphism just says: invoke this method, and the object will know what to do when the time comes.  Ruby (and other dynamic OO languages) take this to an extreme: just call the method; no one's going to check on it until it's actually invoked.  Java forces you to promise the behavior through interfaces, classes, and type checking, but when it comes down to me writing a polymorphic call, Java doesn't really care where that method is coming from.  Just call it!  What could be an easier way to program?!&lt;/p&gt;

&lt;p&gt;When implementing the polymorphic methods, all you have to consider it a very restricted context.  Again, what could be easier?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if&lt;/code&gt;s are necessary to kick things off.  Some code has to actually create the objects which will later make the polymorphic dispatches, but how much of your code consists of creating new objects?  It could probably be delegated to a couple of factories if you really wanted to, and then the "&lt;code&gt;if&lt;/code&gt; problem" would be localized.&lt;/p&gt;

&lt;h2&gt;If X &amp;lt; Y&lt;/h2&gt;

&lt;p&gt;One question does intrigue me: mathematics.  My dissertation involved matrix operations, and I took a couple of scientific computation classes in grad school.  Could I write a QR factorization without &lt;code&gt;if&lt;/code&gt;s?  Could it be done in a more OO way?  This I'm not sure of.  Perhaps the more mathematical the domain, the more &lt;code&gt;if&lt;/code&gt;s?&lt;/p&gt;

&lt;h2&gt;Not Just OO&lt;/h2&gt;

&lt;p&gt;One thing that gets ignored in these arguments is functional programming.  There are a couple ways that FP languages avoid &lt;code&gt;if&lt;/code&gt;s: case analysis, pattern matching, object-oriented extensions, and type classes.  OO extensions are the least interesting in this list because, well, we're already talking about eliminating &lt;code&gt;if&lt;/code&gt;s with OOP.  Case analysis &lt;em&gt;is&lt;/em&gt; the "&lt;code&gt;if&lt;/code&gt; problem", but a case analysis is possibly a misuse of a FP language.  Pattern matching and type classes offer interesting solutions, but they're proving to tickle my interest more than I thought they would.  I'll have to think about the FP solutions to the "&lt;code&gt;if&lt;/code&gt; problem" and blog about it later.&lt;/p&gt;
  
&lt;p&gt;During the meanwhile, all (and especially Andy) should contemplate the precedence and associativity of the phrase "former student and friend".  (Too harsh?  Too bitter?)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-6444173699392463241?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/6444173699392463241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=6444173699392463241' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6444173699392463241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6444173699392463241'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/06/anti-if-campaign.html' title='Anti-If Campaign'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3056390363464490050</id><published>2009-06-04T19:00:00.002-04:00</published><updated>2009-06-04T19:08:30.377-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Why haven't I wondered about this before?</title><content type='html'>&lt;p&gt;I came across this article from InfoQ today: &lt;a href="http://www.infoq.com/news/2009/06/java-without-primitives"&gt;"Original Sin" (Would Java be Better Off Without Primitives?)&lt;/a&gt;.  I've been very impressed and happy with Ruby's commitment to making &lt;em&gt;everything&lt;/em&gt; an object.  I had been indoctrinated into ignoring primitive-versus-pointer distinctions by Scheme and Haskell, so to revert to Fortran/C thinking when I picked Java up was kind of annoying.  My question after reading the article was why I assumed that Java &lt;em&gt;had&lt;/em&gt; to have primitive data types.&lt;/p&gt;

&lt;p&gt;There are some cool tidbits about Java in that article that make it worth reading.  I'll spoil the coolest one: Java exists because Sun couldn't license Smalltalk.  What could have been!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3056390363464490050?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3056390363464490050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3056390363464490050' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3056390363464490050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3056390363464490050'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/06/why-havent-i-wondered-about-this-before.html' title='Why haven&apos;t I wondered about this before?'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3931382891766323368</id><published>2009-05-22T16:22:00.002-04:00</published><updated>2009-05-22T17:00:31.399-04:00</updated><title type='text'>Name your variables, stop picking on the string class, and call methods symmetrically</title><content type='html'>&lt;p&gt;Actually, the talk is &lt;a href="http://mwrc2009.confreaks.com/14-mar-2009-15-35-what-the-ruby-craftsman-can-learn-from-the-smalltalk-master-philippe-hanrigou.html"&gt;"What the Ruby Craftsman Can Learn from the Smalltalk Master"&lt;/a&gt; by Philippe Hanrigou.  In his talk, Philippe covers these three issues because they're interesting in themselves and also to demonstrate what others have discovered before us.  The "others" in this case is Kent Beck and his &lt;i&gt;Smalltalk Best Practice Patterns&lt;/i&gt; book.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naming variables.&lt;/strong&gt;  Philippe discusses Beck's take on variables: name them after their &lt;em&gt;roles&lt;/em&gt;.  I couldn't agree more.  I've ranted here about this before (haven't I?), but I'm convinced that a sign of a good programmer is the ability to find the right names for classes and variables.  I'm &lt;em&gt;almost&lt;/em&gt; convinced that this ability is sufficient and necessary to be a good programmer.  (And, please, no one look at my &lt;a href="http://www.github.com/jdfrens/ciat/"&gt;CIAT project&lt;/a&gt; and some of the class names there.  I'm &lt;em&gt;really&lt;/em&gt; unhappy with them.)&lt;/p&gt;

&lt;p&gt;It saddens me the number of students I've seen who'll use the variable names that first come to mind or are generated by Eclipse.  (My Programming Languages students might want to look over their code for any &lt;code&gt;arg0&lt;/code&gt; variables that are being used in useful methods before I turn in grades next week.)  I've found that a lot of the time that a good variable name &lt;em&gt;is&lt;/em&gt; based on the data type.  For example, I've been writing a lot of interpreters lately.  When I have an integer object that needs to be interpreted, isn't &lt;code&gt;integer&lt;/code&gt; an obvious name?  It does bother me a bit that it's also the data type of the object, &lt;code&gt;IntegerETIR&lt;/code&gt; ("integer expression tree-intermediate-representation").  I can see an argument that I should call the variable "&lt;code&gt;expression&lt;/code&gt;" or even "&lt;code&gt;program&lt;/code&gt;".  Perhaps a good starting point is to use a variation on the data type for the variable name, and if that's too ambiguous or misleading, find a better name for the role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Giving the string class too much responsiblity.&lt;/strong&gt;  Philippe points out all of the methods are being added to the &lt;code&gt;String&lt;/code&gt; class for data conversions: &lt;code&gt;to_f&lt;/code&gt; (meh), &lt;code&gt;to_yaml&lt;/code&gt; (maybe...), &lt;code&gt;to_date&lt;/code&gt; (yikes!), &lt;code&gt;to_blob&lt;/code&gt; (what the...!), etc.  This means to be able to use a string, you'll need all of these other classes.&lt;/p&gt;

&lt;p&gt;The solution is to turn these "to" methods into "from" methods.  Put &lt;code&gt;from_string&lt;/code&gt; into &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;YAML&lt;/code&gt;, &lt;code&gt;Float&lt;/code&gt;, and &lt;code&gt;Blob&lt;/code&gt; classes.  Haskell, too, uses "from" functions.  My understanding is that this is more about the type system, but then I wonder if the type system is telling us something!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symmetry.&lt;/strong&gt;  Philippe ends with an example of a method invoking three other methods.  Here's an example of my own:&lt;/p&gt;
&lt;pre&gt;
def foo()
  dog()
  @zoo.bat()
  cow()
end
&lt;/pre&gt;
&lt;p&gt;It comes down to the readability of the code.  Instead of figuring out what the code is doing, you're asking yourself, why the one instance variable?  I'm reminded of poetry and music where the artist is &lt;em&gt;supposed&lt;/em&gt; to follow a particular form.  The second line of this method is like a limerick of six lines or a haiku with 20 syllables.  &lt;em&gt;"Why did you do that?"&lt;/em&gt;  While this might be dramatic in a poem, this kind of drama is &lt;em&gt;not&lt;/em&gt; wanted in code!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3931382891766323368?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3931382891766323368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3931382891766323368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3931382891766323368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3931382891766323368'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/name-your-variables-stop-picking-on.html' title='Name your variables, stop picking on the string class, and call methods symmetrically'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4164116893851442063</id><published>2009-05-20T20:38:00.002-04:00</published><updated>2009-05-20T20:51:59.451-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Bad breathalyzer code</title><content type='html'>&lt;p&gt;Ed Brayton, author of one of my most favorite blogs &lt;a href="http://scienceblogs.com/dispatches/"&gt;Dispatches from the Culture Wars&lt;/a&gt;, posted something about bad code today: &lt;a href="http://scienceblogs.com/dispatches/2009/05/why_breathalyzer_companies_won.php"&gt;"Why Breathalyzer Companies Won't Release Code"&lt;/a&gt;.  Ed's blog entry is almost entirely a quote of a summary of a court finding.  There you'll find an PDF of the code review.&lt;/p&gt;

&lt;p&gt;I gave that document a quick scan, and it seems really interesting to me.  There's a little bit of pride in me, thinking "oh, I'd never do &lt;em&gt;that&lt;/em&gt;!"  But there's also quite a bit of shame, too, since whenever some software developer does a bad job it reflects poorly on us all.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4164116893851442063?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4164116893851442063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4164116893851442063' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4164116893851442063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4164116893851442063'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/bad-breathalyzer-code.html' title='Bad breathalyzer code'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-14203263270191338</id><published>2009-05-20T14:59:00.003-04:00</published><updated>2009-05-20T15:07:30.183-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='recommendation'/><title type='text'>"Outside-In Development with Cucumber"</title><content type='html'>&lt;p&gt;I just got done watching an &lt;em&gt;excellent&lt;/em&gt; talk from Mountain West Ruby Conference 2009: &lt;a href="http://mwrc2009.confreaks.com/14-mar-2009-15-00-bdd-with-cucumber-ben-mabey.html"&gt;Outside-In Development with Cucumber"&lt;/a&gt; by Ben Mabey.&lt;/p&gt;

&lt;p&gt;The worst thing you could do is think this is just a talk about &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Yes, there's quite a bit about Cucumber in the talk, and if you aren't impressed with it technically, this talk should convince you.  (At least watch until he presents the alternative language options in Cucumber.)&lt;/p&gt;

&lt;p&gt;What I found so great about Ben's talk is that he does a great job giving the motivation for why, when, and how to use Cucumber and RSpec (or TestUnit or whatever).  Even if you're not interested in Ruby or Rails (let alone Cucumber), I'll guarantee you'll get something out of this talk, or your money back.  (Of course, you'll have to pay me first in order to get anything back...)&lt;/p&gt;

&lt;p&gt;I'm really impressed with the way Ben put all this material together.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-14203263270191338?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/14203263270191338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=14203263270191338' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/14203263270191338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/14203263270191338'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/outside-in-development-with-cucumber.html' title='&quot;Outside-In Development with Cucumber&quot;'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2382361864631177383</id><published>2009-05-19T12:04:00.003-04:00</published><updated>2009-05-19T12:09:28.548-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Programming Languages final exam</title><content type='html'>&lt;p&gt;Here's the final exam that I gave to my Programming Languages students this morning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Consider the three languages that we studied this semester and their representative paradigms:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Ruby (or Java, if you like) for object-oriented programming&lt;/li&gt;
  &lt;li&gt;Haskell for functional programming&lt;/li&gt;
  &lt;li&gt;Prolog for logic programming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick one of the following:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Write one (or more) haiku for each language.&lt;/li&gt;
  &lt;li&gt;Write one (or more) limerick for each language.&lt;/li&gt;
  &lt;li&gt;Write one sonnet for each language.  (This one might be worth extra credit.)&lt;/li&gt;
  &lt;li&gt;Write one short story about the three languages (or one story per language).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whichever literary form you pick, be sure to highlight the strength of each language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One student wanted to know if a ballad was okay.  I offered extra credit if it could be set to a Scorpions song.  (Not that I'm a huge Scorpions fan, but for some reason they define the ballad genre for me.)  Personally, I'm hoping for a bawdy limerick or three.&lt;/p&gt;

&lt;p&gt;It's due by the middle of next week.  I may share some of the good ones here.  Feel free to contribute your own in a comment.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2382361864631177383?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2382361864631177383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2382361864631177383' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2382361864631177383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2382361864631177383'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/programming-languages-final-exam.html' title='Programming Languages final exam'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5865806958295818729</id><published>2009-05-16T13:16:00.002-04:00</published><updated>2009-05-16T13:24:26.153-04:00</updated><title type='text'>Opinions on RSS and Atom feeds and Rails</title><content type='html'>&lt;p&gt;I'm getting ready to implement RSS and/or Atom feeds for my (soon to be former) &lt;a href="http://cs.calvin.edu/"&gt;department&lt;/a&gt;, and I have a few questions that I hope some of you can help answer:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RSS 1.0 or 2.0 or both?&lt;/li&gt;
  &lt;li&gt;Atom or RSS or both?&lt;/li&gt;
  &lt;li&gt;Any good Rails plugins for generating feeds?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One issue I have is that the feed will include not only news items (e.g., "Student X won an award!", "IT jobs on the rise!"), it will also include announcements of talks and other department-related events (e.g., "Jimmy talking tomorrow!", "Picnic next week!").&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Is it a good idea to mix event announcements in with the news items?&lt;/li&gt;
  &lt;li&gt;How often can I make the announcement?  My thought is to add it to the feed a week before and again the day before.  (This is when we send out email announcements.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, yes, all of our news and events are &lt;em&gt;so&lt;/em&gt; exciting that they deserve exclamation points all the time!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5865806958295818729?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5865806958295818729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5865806958295818729' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5865806958295818729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5865806958295818729'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/opinions-on-rss-and-atom-feeds-and.html' title='Opinions on RSS and Atom feeds and Rails'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7103921270260359942</id><published>2009-05-09T08:00:00.000-04:00</published><updated>2009-05-09T08:00:00.712-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Minimal Palindrome, Efficiency of My Haskell Code</title><content type='html'>&lt;p&gt;One thing I do rely on in my &lt;a href="http://jdfrens.blogspot.com/2009/05/minimal-palindrome-my-haskell-code.html"&gt;Haskell code to compute a minimal palindrome&lt;/a&gt; is the &lt;a href="http://en.wikipedia.org/wiki/Lazy_evaluation"&gt;lazy evaluation&lt;/a&gt; of Haskell.&lt;/p&gt;

&lt;p&gt;My first computation in the body of the function &lt;code&gt;makeMinimalPalindrome&lt;/code&gt; (which I'll abbreviate "&lt;code&gt;mmp&lt;/code&gt;") is to map a list-duplicating function over &lt;code&gt;n&lt;/code&gt; numbers (where &lt;code&gt;n&lt;/code&gt; is the length of the list).  This sounds like an &lt;code&gt;n&lt;/code&gt;&lt;sup&gt;2&lt;/sup&gt; algorithm.  I concatenate the original list with all of those lists.  That could also be quadratic in &lt;code&gt;n&lt;/code&gt; (depends how concatenation is implemented).  Find just the palindromes, quadratic.  Return the first element of that list (constant time, but who cares by now!).  Total time: quadratic.&lt;/p&gt;

&lt;p&gt;That's if you're in a naive language like C.&lt;/p&gt;

&lt;p&gt;Lazy evaluation bottles up those computations until they're &lt;em&gt;known&lt;/em&gt; to be needed.  And, in turns out, that this ends up reversing what's "done first".&lt;/p&gt;

&lt;p&gt;So who needs those &lt;code&gt;mmp&lt;/code&gt; computations?  Well, I'm running unit tests, and my driver will print an error if an assertion failed and will count successes and failures.  So all of my assertions for &lt;code&gt;mmp&lt;/code&gt; need to be computed.  Let's consider one of them: &lt;code&gt;mmp [1, 2, 1]&lt;/code&gt;.  You'd expect this to waste time with the different suffices just to discover it's already a palindrome.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;outermost&lt;/em&gt; function call of &lt;code&gt;mmp&lt;/code&gt; is considered first.  &lt;code&gt;head&lt;/code&gt; only requires the &lt;em&gt;first element&lt;/em&gt; of its argument to be evaluated.  Already at this point you should see the savings.  The code will &lt;em&gt;not&lt;/em&gt; compute every palindrome candidate.  The &lt;code&gt;head&lt;/code&gt; call requires the &lt;code&gt;filter&lt;/code&gt; to find just the first palindrome.  &lt;code&gt;filter&lt;/code&gt; will trigger the two &lt;code&gt;map&lt;/code&gt;s only enough times to find that first palindrome.&lt;/p&gt;

&lt;p&gt;I'm making this sound like the functions are passing their need along.  But it's really the functions evaluate their arguments until they produce the data that they need.&lt;/p&gt;

&lt;p&gt;Consider the running time of &lt;code&gt;mmp [1, 2, 1]&lt;/code&gt;.  &lt;code&gt;head&lt;/code&gt; is constant time.&lt;/code&gt;  The &lt;code&gt;filter&lt;/code&gt; should stop on the very first result, and checking that it's a palindrome is linear time.  Both of the &lt;code&gt;map&lt;/code&gt;s will have to be triggered only once, and the functions they map are linear as well.  Finally, constructing &lt;code&gt;ns&lt;/code&gt; is also linear.&lt;/p&gt;

&lt;p&gt;You can't do better in any other language, not at the this big-O level.  Just to check to make sure you have a palindrome is linear time.  The constants on their linear complexities will definitely be different, but then we get into issues of implementation and adeptness of wielding a language.&lt;/p&gt;

&lt;p&gt;The original problem is so academic (easy to understand but impractical in any real program) that I'm not sure it's worth analyzing much further.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7103921270260359942?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7103921270260359942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7103921270260359942' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7103921270260359942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7103921270260359942'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/minimal-palindrome-efficiency-of-my.html' title='Minimal Palindrome, Efficiency of My Haskell Code'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8466307213680565891</id><published>2009-05-08T13:30:00.002-04:00</published><updated>2009-05-08T13:30:00.237-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='abstraction'/><title type='text'>Minimal Palindrome, My Natural Haskell Code</title><content type='html'>&lt;p&gt;In my previous post, I wrote about my &lt;a href="http://jdfrens.blogspot.com/2009/05/minimal-palindrome-my-haskell-code.html"&gt;Haskell code to compute a "minimal palindrome"&lt;/a&gt;.  I don't want to belabor this one example because it's really not that useful a computation, but a few things do strike me.  In this blog post, I'm going to talk about the natural flow of my algorithm.  In the next post, I'll talk about the efficiency of the algorithm.&lt;/p&gt;

&lt;p&gt;So... I find this solution &lt;em&gt;natural&lt;/em&gt;.  What do I mean by that?  How can I get most of you to stop laughing?  First, I'm &lt;em&gt;not&lt;/em&gt; saying that it's natural to any program as written.  A reasonably experienced Haskeller (with two semesters of programming experience?) could make sense of it without troubles.  For those using other languages, it might help if the code were rewritten with some crutch... I mean... helper variables:&lt;/p&gt;

&lt;pre&gt;
&lt;span class='hs-definition'&gt;makeMinimalPalindrome&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; 
  &lt;span class='hs-keyword'&gt;let&lt;/span&gt;
    &lt;span class='hs-varid'&gt;suffices&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;map&lt;/span&gt; &lt;span class='hs-varid'&gt;makeSuffix&lt;/span&gt; &lt;span class='hs-varid'&gt;ns&lt;/span&gt;
    &lt;span class='hs-varid'&gt;allLists&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;map&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;list&lt;/span&gt;&lt;span class='hs-varop'&gt;++&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-varid'&gt;suffices&lt;/span&gt;
    &lt;span class='hs-varid'&gt;palindromes&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;filter&lt;/span&gt; &lt;span class='hs-varid'&gt;isPalindrome&lt;/span&gt; &lt;span class='hs-varid'&gt;allLists&lt;/span&gt;
  &lt;span class='hs-keyword'&gt;in&lt;/span&gt;
    &lt;span class='hs-varid'&gt;head&lt;/span&gt; &lt;span class='hs-varid'&gt;palindromes&lt;/span&gt;
      &lt;span class='hs-keyword'&gt;where&lt;/span&gt; &lt;span class='hs-varid'&gt;ns&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;reverse&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;[&lt;/span&gt;&lt;span class='hs-num'&gt;1&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;..&lt;/span&gt;&lt;span class='hs-varid'&gt;length&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;]&lt;/span&gt;
            &lt;span class='hs-varid'&gt;makeSuffix&lt;/span&gt; &lt;span class='hs-varid'&gt;n&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;drop&lt;/span&gt; &lt;span class='hs-varid'&gt;n&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;reverse&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt;^D
&lt;/pre&gt;

&lt;p&gt;By the way, I &lt;em&gt;know&lt;/em&gt; that this code works because I have unit tests, and they still pass after these refactorings.  If you start with the idea that you're going to try every possible suffix to create the minimal palindrome, this is a natural order to build up the code.&lt;/p&gt;

&lt;p&gt;I'd wager, though, that most of you indoctrinated early with Pascal or C or C++ or Java are still shaking your heads.  But take a step back.  What solution are you imagining in your head?  There's a loop or two and arrays, right?  Index operators?  &lt;em&gt;Why work with the data at that level?&lt;/em&gt;  That's &lt;em&gt;not&lt;/em&gt; how you'd describe the algorithm to your mom (unless she's a C programmer, too).  The more I play with Haskell and Ruby, I find I get more power out of them when I try to write the most hand waving algorithms I can.  "Concatenate these lists."  How?  I don't know; I don't care!  "Reverse this list."  Just do it!&lt;/p&gt;

&lt;p&gt;Much of this "hand waving" attitude is just a desire to use higher and higher abstractions.  That's what high-level programming has been about all along, right?  But I'm really beginning to question whether a student in a CS1 course should even know how to index an array.  Use a list and higher level operators (where I'd include Java's "foreach" a "high level operator").&lt;p&gt;

&lt;p&gt;Back to this particular code.  The real kicker is that many of you are quite worried about all of those lists I'm creating with the reverses and dropping and concatenating.  What happens if &lt;code&gt;list&lt;/code&gt; is already a palindrome?  Your C code would recognize this immediately and stop, right?  &lt;em&gt;So will this code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Okay, that's a bit of a lie, but I wanted a good teaser for you to look forward to my next blog post!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8466307213680565891?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8466307213680565891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8466307213680565891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8466307213680565891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8466307213680565891'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/minimal-palindrome-my-natural-haskell.html' title='Minimal Palindrome, My Natural Haskell Code'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1776142793755742226</id><published>2009-05-08T11:52:00.001-04:00</published><updated>2009-05-08T11:58:41.528-04:00</updated><title type='text'>RubyMine for Rails development</title><content type='html'>&lt;p&gt;I saw a version of IntelliJ in action two years ago, and I wasn't particularly impressed.  It is a great IDE, but it didn't seem to offer anything over Eclipse.  (The version I was using was also quite buggy, but I'm trying not to hold that against it.)&lt;/p&gt;

&lt;p&gt;But the Ruby on Rails support in Eclipse (and Aptana) have greatly disappointed me.  NetBeans is good, but more than a big sluggish.  TextMate doesn't seem like quite enough for me for Ruby on Rails.  So I thought I'd give &lt;a href="http://www.jetbrains.com/ruby/index.html"&gt;RubyMine&lt;/a&gt; from the IntelliJ guys (&lt;a href="http://www.jetbrains.com/"&gt;JetBrains&lt;/a&gt;) a try.&lt;/p&gt;

&lt;p&gt;First impression: pretty slick!  It runs nice and speedy on my MacBook (2.0 GHz with 4 GB of RAM).  The first time I started it, it took some time to get acquainted with my environment, but it's been reasonably speedy ever since.&lt;/p&gt;

&lt;p&gt;"Slick" also means "eye candy".  It's not iPhone-level eye candy (which would count against it), but it's good and appropriate IDE eye candy.  RSpec (and, I assume, Test::Unit) runs in a special green-bar/red-bar window.  Syntax highlighting is good with the default colors.&lt;/p&gt;

&lt;p&gt;One place where RubyMine really excels is with code navigation.  It seems to understand the Rails defaults so that it knows what view to jump to when you're in a particular controller action.  It also knows what all to rename with a Rename refactoring (watch &lt;a href="http://www.jetbrains.com/ruby/documentation/index.html"&gt;the rename refactoring demo&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;RubyMine also has excellent version-control support for CVS (I think), subversion, and git (oooo!).&lt;/p&gt;

&lt;p&gt;The primary complaint I have is that there's apparently no cucumber support yet.  The little Googling I did seemed to indicate that cucumber support is on its way, but not until this fall.  Boo!&lt;/p&gt;

&lt;p&gt;But if you're looking for a Rails IDE, I'd certainly recommend trying out RubyMine.  It might even be worth it's $99 price tag.  (I'm working on open-source projects right now, so I could get it for free.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1776142793755742226?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1776142793755742226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1776142793755742226' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1776142793755742226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1776142793755742226'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/rubymine-for-rails-development.html' title='RubyMine for Rails development'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5843745278906274327</id><published>2009-05-07T15:13:00.001-04:00</published><updated>2009-05-07T15:15:06.680-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Minimal Palindrome, My Haskell Code</title><content type='html'>&lt;p&gt;A couple weeks ago I &lt;a href="http://jdfrens.blogspot.com/2009/04/programming-challenge-minimal.html"&gt;proposed a programming challenge:&lt;/a&gt; write a Haskell function to compute a "minimal palindrome" without using explicit recursion.  One of the things I've tried to get my programming-language students to appreciate this semester is the &lt;em&gt;true&lt;/em&gt; power of functional programming: functions as first-class values.&lt;/p&gt;

&lt;p&gt;So, back to the challenge.  A minimal palindrome is taking &lt;code&gt;[1, 2, 3]&lt;/code&gt; and returning &lt;code&gt;[1, 2, 3, 2, 1]&lt;/code&gt; (the &lt;code&gt;3&lt;/code&gt; is not repeated).  It's also taking &lt;code&gt;[1, 2, 1]&lt;/code&gt; and returning &lt;code&gt;[1, 2, 1]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I already had this function to recognize a palindrome:&lt;/p&gt;

&lt;pre&gt;
&lt;span class='hs-definition'&gt;isPalindrome&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt; &lt;span class='hs-varop'&gt;==&lt;/span&gt; &lt;span class='hs-varid'&gt;reverse&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Now there might be a clever algorithm using a string matching algorithm for computing the minimal palindrome, but I went more brute force.  I started with this observation: if &lt;code&gt;pal&lt;/code&gt; is returned by &lt;code&gt;makeMinimalPalindrome&amp;nbsp;list&lt;/code&gt;, then&lt;/p&gt;
 
&lt;pre&gt;
pal == list ++ (drop n $ reverse list)
&lt;/pre&gt;

&lt;p&gt;for the smallest &lt;code&gt;n&lt;/code&gt;.  (For those thrown by the syntax, &lt;code&gt;drop n $ reverse list&lt;/code&gt; can be rewritten as &lt;code&gt;drop n (reverse list)&lt;/code&gt;.  It's a handy operator once you get used to it.)  My brute-force algorithm was to try every possible &lt;code&gt;n&lt;/code&gt;, from &lt;code&gt;length&amp;nbsp;list&lt;/code&gt; down to &lt;code&gt;1&lt;/code&gt;.  (I don't have to try &lt;code&gt;0&lt;/code&gt; because &lt;code&gt;1&lt;/code&gt; is guaranteed to give me a palindrome.)  From this list of results, I filter out the palindromes and return the one with the smallest &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The code:&lt;/p&gt;

&lt;pre&gt;
&lt;span class='hs-definition'&gt;makeMinimalPalindrome&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; 
  &lt;span class='hs-varid'&gt;head&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;filter&lt;/span&gt; &lt;span class='hs-varid'&gt;isPalindrome&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;map&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;list&lt;/span&gt;&lt;span class='hs-varop'&gt;++&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;map&lt;/span&gt; &lt;span class='hs-varid'&gt;makeSuffix&lt;/span&gt; &lt;span class='hs-varid'&gt;ns&lt;/span&gt;
    &lt;span class='hs-keyword'&gt;where&lt;/span&gt; &lt;span class='hs-varid'&gt;ns&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;reverse&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;[&lt;/span&gt;&lt;span class='hs-num'&gt;1&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;..&lt;/span&gt;&lt;span class='hs-varid'&gt;length&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;]&lt;/span&gt;
          &lt;span class='hs-varid'&gt;makeSuffix&lt;/span&gt; &lt;span class='hs-varid'&gt;n&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;drop&lt;/span&gt; &lt;span class='hs-varid'&gt;n&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;reverse&lt;/span&gt; &lt;span class='hs-varid'&gt;list&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;ns&lt;/code&gt; are the &lt;code&gt;n&lt;/code&gt;s from &lt;code&gt;length list&lt;/code&gt; down to &lt;/code&gt;1&lt;/code&gt;.  &lt;code&gt;makeSuffix&lt;/code&gt; computes a reversed suffix for the palindrome.  Reading the real body of the function from right to left, the first map creates all of the suffices; the second adds them onto the original list; the filter finds only the palindromes; and &lt;code&gt;head&lt;/code&gt; returns the first one in the list (of lists).  Since I start &lt;code&gt;ns&lt;/code&gt; at &lt;code&gt;length&amp;nbsp;list&lt;/code&gt;, I'm guaranteed to get the minimal palindrome.&lt;/p&gt;

&lt;p&gt;There are some more things to say about this code, but I'm going to save them for some future blog entries.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5843745278906274327?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5843745278906274327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5843745278906274327' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5843745278906274327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5843745278906274327'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/05/minimal-palindrome-my-haskell-code.html' title='Minimal Palindrome, My Haskell Code'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3512573105320352943</id><published>2009-04-29T07:56:00.002-04:00</published><updated>2009-04-29T08:02:13.415-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Seven Stages of Unit Testing</title><content type='html'>&lt;p&gt;Came across an interesting list this morning: &lt;a href="http://codebetter.com/blogs/karlseguin/archive/2009/04/27/the-7-phases-of-unit-testing.aspx"&gt;"The 7 Phases of Unit Testing"&lt;/a&gt;.  It does a pretty good job of describing the phases I went through.  Get started now, because phase 7 is great!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3512573105320352943?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3512573105320352943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3512573105320352943' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3512573105320352943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3512573105320352943'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/04/seven-stages-of-unit-testing.html' title='Seven Stages of Unit Testing'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8061650062625227248</id><published>2009-04-28T12:35:00.002-04:00</published><updated>2009-04-28T12:40:43.584-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='code smells'/><title type='text'>Testing Smells</title><content type='html'>&lt;p&gt;Came across this blog post from Jake Scruggs &lt;a href="http://jakescruggs.blogspot.com/2009/04/smells-of-testing-signs-your-tests-are.html"&gt;"Smells of Testing (signs your tests are bad)
"&lt;/a&gt;.  I would have loved to be at this talk.  I've been thinking of some of these smells myself, and they seem to have started on some good ideas here.  One idea I'd like to throw into the mix: some of these smells indicate problems with the &lt;em&gt;computation&lt;/em&gt; code, not the tests.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8061650062625227248?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8061650062625227248/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8061650062625227248' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8061650062625227248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8061650062625227248'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/04/testing-smells.html' title='Testing Smells'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1895688638453224652</id><published>2009-04-22T13:20:00.002-04:00</published><updated>2009-04-22T13:30:12.646-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Monads in Ruby</title><content type='html'>&lt;p&gt;Yes, &lt;em&gt;Ruby&lt;/em&gt;.  Monads.  In Ruby.&lt;/p&gt;

&lt;p&gt;I came across a blog entry by Bill Six called &lt;a href="http://billsix.blogspot.com/2009/04/functional-patterns-in-ruby-monads.html"&gt;Functional Patterns in Ruby: Monads&lt;/a&gt;.  I won't repeat what Bill has written there; I'm just curious what Haskellers think of this.&lt;/p&gt;

&lt;p&gt;What I find really interesting is that like all type issues, the move from Haskell to Ruby means moving their resolution from compile type to run time.  But I get the sense from this monad library that these Ruby monads are just as reliable as Haskell's.&lt;/p&gt;

&lt;p&gt;BTW, Firefox didn't like how I was spelling "monads".  It recommended "nomads" or "gonads" instead.  (And in my next post, I'll tell a fart joke.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1895688638453224652?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1895688638453224652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1895688638453224652' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1895688638453224652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1895688638453224652'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/04/monads-in-ruby.html' title='Monads in Ruby'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7949049161984286749</id><published>2009-04-14T18:06:00.003-04:00</published><updated>2009-04-14T18:19:40.919-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='programming challenge'/><title type='text'>Programming challenge: minimal palindrome</title><content type='html'>&lt;p&gt;I gave my &lt;a href="http://cs.calvin.edu/~cs214/"&gt;Programming Language&lt;/a&gt; students a challenge to write a Haskell function that computes a "minimal palindrome".  A "computed palindrome" is reversing the list and appending it to the original list: &lt;code&gt;makePalindrome [1,2,3]&lt;/code&gt; results in &lt;code&gt;[1,2,3,3,2,1]&lt;/code&gt;.  It amounts to one line of code in Haskell.&lt;/p&gt;

&lt;p&gt;After computing a few of these, you'll notice that the middle elements of the computed palindrome (there are always two in the middle) are the same.  That's just a property of the computation.  However, what's the computed palindrome of &lt;code&gt;[1,2,1]&lt;/code&gt;?  If there's an official standard, I'd like to know, but I've taken it to be &lt;code&gt;[1,2,1,1,2,1]&lt;/code&gt; because it's really easy to compute.&lt;/p&gt;

&lt;p&gt;But then the idea of computing a "minimal palindrome" is kind of interesting.  The minimal palindrome is the shortest list that is a palindrome and contains the original list as a prefix.  So the minimal palindrome of &lt;code&gt;[1,2,1]&lt;/code&gt; would be &lt;code&gt;[1,2,1]&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;It turned out this was trickier to do in Haskell (without using explicit recursion) than I had thought.  But it's still quite doable.  I came up with a solution that's three lines of code, and I believe because of Haskell's lazy evaluation is fairly efficient.&lt;/p&gt;

&lt;p&gt;I'm curious what others might come up with before I reveal my solution.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7949049161984286749?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7949049161984286749/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7949049161984286749' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7949049161984286749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7949049161984286749'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/04/programming-challenge-minimal.html' title='Programming challenge: minimal palindrome'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7132094337427076741</id><published>2009-04-07T18:30:00.003-04:00</published><updated>2009-04-07T19:05:07.404-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>Test::Unit Tests as RSpec Examples</title><content type='html'>&lt;p&gt;I've been doing (or trying to do) a bit of Ruby on Rails, and I end up looking up information more than once as I'm learning new techniques and solving new problems. It occurs to
me that if I'm having trouble with some of these things, maybe others are as
well. And through the magic of Google and Yahoo searches, maybe they'll find
my solutions helpful&amp;mdash;but only if I post them here!&lt;/p&gt;

&lt;p&gt;Plus, if I've done something really stupid (or even mildly stupid), other can correct me.&lt;/p&gt;

&lt;p&gt;For this blog post, I'm trying to switch from using Test::Unit in my Rails apps to RSpec.
Presumably, Test::Unit-style testing can be &lt;a href="http://blog.davidchelimsky.net/2009/2/2/rspec-works-with-test-unit"&gt;embedded
in RSpec examples&lt;/a&gt;. Unfortunately, Chelimsky's post only says that it
&lt;em&gt;can&lt;/em&gt; be done, not exactly how, and RSpec for Rails makes it
trickier.  So I collected a few tips here.  Some are relatively obvious, but I find myself worried if I come up with an obvious solution that might be too simple.&lt;/p&gt;

&lt;h2&gt;The Test::Unit to RSpec Transformation&lt;/h2&gt;

&lt;p&gt;I kept to Rails' testing standard: model-tests as "unit tests" and
controller/view tests as "functional tests". So the first step was to copy
from &lt;code&gt;test/unit/&lt;/code&gt; into &lt;code&gt;spec/models/&lt;/code&gt;; the second was to
copy from &lt;code&gt;test/functional/&lt;/code&gt; into &lt;code&gt;spec/controllers&lt;/code&gt;. I
figured that I'd refactor out of the controller tests into view tests as
needed.&lt;/p&gt;

&lt;p&gt;Running the specs resulted in many errors.  Here's a mildly sorted list of errors and my resolutions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shoulda tests are &lt;em&gt;not&lt;/em&gt; examples!&lt;/strong&gt; This problem is silent.  I used the fantastic
Shoulda gem for my Test::Unit tests. Unfortunately, the &lt;code&gt;should&lt;/code&gt;
directive from Shoulda does &lt;em&gt;nothing&lt;/em&gt; to trigger an example or an
error. So they don't run, and you're never told! There's probably some clever
way to deal with this, but I've been too lazy to figure it out. My solution: I ran each example file individually, and when I got only 1 example, I had some unconverted tests.&lt;/p&gt;

&lt;p&gt;Incidentally, inheriting from &lt;code&gt;Test::Unit::TestCase&lt;/code&gt; and writing normal test methods (starting with &lt;code&gt;test_&lt;/code&gt;) works just fine.  My model examples are still just Test::Unit tests.  The problem here was with &lt;code&gt;should&lt;/code&gt; from the Shoulda gem.&lt;/p&gt;

&lt;p&gt;I thought I about grepping the files for "should", but I didn't imagine it would save me &lt;em&gt;that&lt;/em&gt; much time.  Perhaps the more clever solution would be to redefine &lt;code&gt;should&lt;/code&gt; in some way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RSpec can't find &lt;code&gt;test_helper.rb&lt;/code&gt;.&lt;/strong&gt; You don't
want it to. Instead, &lt;code&gt;require&lt;/code&gt; &lt;code&gt;spec_helper.rb&lt;/code&gt;. At the same
time, I dropped the redefinition of &lt;code&gt;rescue_action(e)&lt;/code&gt; since it appears to be unnecessary for RSpec.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Helper methods from &lt;code&gt;test_helper.rb&lt;/code&gt; can't be
found.&lt;/strong&gt; Well, duh! I moved some of them to
&lt;code&gt;spec_helper.rb&lt;/code&gt;. Others I rewrote or even dropped because they
solved problems that I didn't have with RSpec. Take this as an opportunity to
re-evaluate your helper methods: are they really necessary and helpful? is
there a better RSpec way to do it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;response&lt;/code&gt; is undefined.&lt;/strong&gt; I got this in my
controller examples when I started using the RSpec API. This can be solved by
using &lt;code&gt;@response&lt;/code&gt;, but I don't think this is the best solution. See
the next problem and solution&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;redirect_to&lt;/code&gt; (an RSpec matcher) is undefined.&lt;/strong&gt; This frustrated me
for quite a while, and it's the primary motivation for writing this blog entry
because I'm quite sure I've had to look up the solution more than once.  Again,
this is in a controller example, and the problem is that controller-specific
helpers provided by RSpec and RSpec for Rails aren't automatically available. So
the solution was to change the class definition from&lt;/p&gt;

&lt;pre&gt;
class FaqControllerTest &amp;lt; Test::Unit::TestCase
&lt;/pre&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;pre&gt;
describe FaqController do
&lt;/pre&gt;

&lt;p&gt;I also deleted the original Test::Unit &lt;code&gt;setup&lt;/code&gt; method.  This doesn't seem to be necessary, but it also doesn't break anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing fixtures.&lt;/strong&gt; Copy the fixtures from
&lt;code&gt;test/fixtures/&lt;/code&gt; to &lt;code&gt;spec/fixtures/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controller examples failing on view expectations.&lt;/strong&gt; By
default, RSpec does not actually render the views when running a controller
spec. Add &lt;code&gt;integrate_views&lt;/code&gt; in the &lt;code&gt;describe&lt;/code&gt; block for
the controller spec.&lt;/p&gt;

&lt;h2&gt;Cucumber Stories?&lt;/h2&gt;

&lt;p&gt;Uh... well... you see... I don't really have any integration tests. Since
my original apps weren't using mock objects, I don't find this to be a
terrible thing, but I'm also not proud of it.&lt;/p&gt;

&lt;p&gt;Trust me. From here on out, though, I'll be writing Cucumber stories for
all new features (and for old features as need be).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7132094337427076741?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7132094337427076741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7132094337427076741' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7132094337427076741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7132094337427076741'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/04/testunit-tests-as-rspec-examples.html' title='Test::Unit Tests as RSpec Examples'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1370289940731519180</id><published>2009-04-05T19:52:00.003-04:00</published><updated>2009-04-05T19:56:50.160-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><title type='text'>Taming Side Effects</title><content type='html'>&lt;p&gt;This afternoon, I watched &lt;a href="http://www.infoq.com/presentations/Taming-Effect-Simon-Peyton-Jones"&gt;"Taming Effects with Functional Programming"&lt;/a&gt;, a presentation by Simon Peyton-Jones.  Peyton-Jones is wicked smart, and he gives a good presentation.  Doesn't hurt that everything he says makes my dissertation relevant for &lt;em&gt;today&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;If you ever wonder why I or anyone else goes on and on about the benefits of functional programming (and Haskell), you &lt;em&gt;must&lt;/em&gt; watch this presentation.  If you're already convinced, you'll appreciate the confirmation.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1370289940731519180?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1370289940731519180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1370289940731519180' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1370289940731519180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1370289940731519180'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/04/taming-side-effects.html' title='Taming Side Effects'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1750369211280362258</id><published>2009-03-24T10:52:00.001-04:00</published><updated>2009-03-24T10:52:07.809-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><title type='text'>Another Euler polyglot</title><content type='html'>&lt;p style="clear: both"&gt;I came across someone else who's writing up &lt;a href="http://projecteuler.net"&gt;Project Euler&lt;/a&gt; solutions in &lt;a href="http://github.com/lgastako/polyeuler/tree"&gt;multiple languages&lt;/a&gt;.&lt;/p&gt;  &lt;p style="clear: both"&gt;lgastako (a.k.a. "John", if his GitHub profile is to be trusted) has an impressive list of languages: C, Clojure, Erlang, Java, Javascript, Common LISP, Lua, Pascal, Perl, Python, Ruby, Scheme, and Haskell. Our overlaps are interesting: Haskell, Ruby, Python, and Erlang. I'd go so far as to say these are probably the most important languages to &lt;em&gt;learn&lt;/em&gt; these days. (Finding a job using these languages would be great, too, but the concepts they teach you are fantastic.)&lt;/p&gt;  &lt;p style="clear: both"&gt;The biggest difference seems to be that he isn't writing unit tests. That and his GitHub repository that gets him noticed by the GitHub people. (I'm not bitter, of course.)&lt;/p&gt;  &lt;p style="clear: both"&gt;For some reason, when I first read a description of Igastako's project, I thought he was working on a language translator. That is, he was writing a solution to a Project-Euler problem in one language which would produce solutions in other languages. I've thought about doing this myself, but it wouldn't give me the hands-on work that is needed to learn a language. On the other hand, I've grown tired of writing the unit tests in multiple languages. Perhaps that's a place where I could do some language generation.&lt;/p&gt;  &lt;p style="clear: both"&gt;I do offer this one bit of advice for Igastako: for the sake of everything holy, please do not try to use Prolog to solve these problems. Save yourself the pain and suffering. Syntactically, you'll get enough from Erlang. Semantically, Prolog offers nothing for the types of problems from Project Euler. Seriously, try &lt;a href="http://www.muppetlabs.com/~breadbox/bf/"&gt;Brainf*ck&lt;/a&gt; or &lt;a href="http://compsoc.dur.ac.uk/whitespace/"&gt;Whitespace&lt;/a&gt; instead. Find different problems for Prolog.&lt;/p&gt;  &lt;br class="final-break" style="clear: both" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1750369211280362258?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1750369211280362258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1750369211280362258' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1750369211280362258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1750369211280362258'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/03/another-euler-polyglot.html' title='Another Euler polyglot'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3844640843602669683</id><published>2009-02-28T06:57:00.003-05:00</published><updated>2009-02-28T06:59:12.553-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Hacking Ruby's Default Parameters</title><content type='html'>&lt;p&gt;It's been quiet on this blog here for a while.  ("&lt;em&gt;Too&lt;/em&gt; quiet...")  I just had to share this: &lt;a href="http://blog.mobalean.com/2009/02/28/hacking-rubys-default-arguments"&gt;Hacking Ruby's default arguments"&lt;/a&gt;.  Factorial defined in the &lt;em&gt;parameter list&lt;/em&gt;.  Yikes!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3844640843602669683?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3844640843602669683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3844640843602669683' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3844640843602669683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3844640843602669683'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2009/02/hacking-rubys-default-parameters.html' title='Hacking Ruby&apos;s Default Parameters'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5288880965096658213</id><published>2008-12-21T13:00:00.001-05:00</published><updated>2008-12-21T13:00:00.444-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><title type='text'>Language Performance on PE Problem #4</title><content type='html'>&lt;p&gt;In a &lt;a href="http://jdfrens.blogspot.com/2008/12/pe-problem-4-in-all-languages.html"&gt;previous blog post&lt;/a&gt;, I wrote about my solution to the fourth Project Euler problem.  My brute force algorithm was quadratic, and with some clever mathematics I figured I could reduce the search space quite a bit.  But the Project Euler website's question for Problem #4 could be solved in less than four seconds by my programs.  So I never looked for a better algorithm.&lt;/p&gt;

&lt;p&gt;But I became curious about the performance of my languages.  So I timed each one to see how well they performed.&lt;/p&gt;

&lt;p&gt;But first, let me reiterate my position on efficiency.  I start with Knuth: "Premature optimization is the root of all evil."  My policy is that if you want things faster, you have to use a profiler and optimize the bits that will give you the best payoff.&lt;/p&gt;

&lt;p&gt;However, I'm not looking to improve my code.  (In fact, I actually changed my Ruby solution and made it worse!)  I was just curious how the languages compared to each other.&lt;/p&gt;

&lt;h4&gt;The Timing Results&lt;/h4&gt;

&lt;p&gt;The numbers below come from one set of trials.  I ran several set of trials, and they all came out like this.  Some things to note:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;Interpreted versus compiled:
  &lt;ul&gt;
   &lt;li&gt;Ruby and Prolog were always interpreted.&lt;/li&gt;
   &lt;li&gt;Python seems to compile something the first time it runs.&lt;/li&gt;
   &lt;li&gt;Erlang compiles to a byte code; Haskell compiles to native code; both compile before the timed execution.&lt;/li&gt;
  &lt;/ul&gt;
 &lt;/li&gt;
 &lt;li&gt;I measured wall-clock time since it's the overall performance I'm interested in, not just processor time.&lt;/li&gt;
&lt;/ul&gt;

&lt;table summary="running time" border="1"&gt;
 &lt;tr&gt;&lt;th rowspan="2"&gt;Language&lt;/th&gt;&lt;th colspan="3"&gt;Run/Running Time (in seconds)&lt;/th&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;th&gt;1st&lt;/th&gt;&lt;th&gt;2nd&lt;/th&gt;&lt;th&gt;3rd&lt;/th&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Erlang&lt;/td&gt; &lt;td&gt;2.69&lt;/td&gt;&lt;td&gt;2.28&lt;/td&gt;&lt;td&gt;2.75&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Haskell&lt;/td&gt;&lt;td&gt;0.43&lt;/td&gt;&lt;td&gt;0.40&lt;/td&gt;&lt;td&gt;0.40&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Prolog&lt;/td&gt; &lt;td&gt;3.07&lt;/td&gt;&lt;td&gt;2.49&lt;/td&gt;&lt;td&gt;2.56&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Python&lt;/td&gt; &lt;td&gt;3.72&lt;/td&gt;&lt;td&gt;1.06&lt;/td&gt;&lt;td&gt;1.31&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Ruby&lt;/td&gt;   &lt;td&gt;3.92&lt;/td&gt;&lt;td&gt;3.89&lt;/td&gt;&lt;td&gt;3.91&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Ruby 1.9&lt;/td&gt;&lt;td&gt;2.34&lt;/td&gt;&lt;td&gt;2.35&lt;/td&gt;&lt;td&gt;2.34&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Ruby&lt;/td&gt;   &lt;td&gt;1.89&lt;/td&gt;&lt;td&gt;1.87&lt;/td&gt;&lt;td&gt;1.87&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Ruby 1.9&lt;/td&gt;&lt;td&gt;1.03&lt;/td&gt;&lt;td&gt;0.98&lt;/td&gt;&lt;td&gt;0.95&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;Surprises and a Non-Surprise&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Surprise #1:&lt;/strong&gt; Haskell wins!  Decisively!  I'm &lt;em&gt;not&lt;/em&gt; that surprised that it won, but I am surprised that it's &lt;em&gt;so much better&lt;/em&gt;.  So why did it win?  Some must be due to compilation to native code.  I also think that the &lt;a href="http://haskell.org/ghc/"&gt;GHC guys&lt;/a&gt; &lt;em&gt;really&lt;/em&gt; know what they're doing!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Surprise #2:&lt;/strong&gt; Erlang doesn't perform very well.  For some reason, I thought it would do better.  However, I may not be compiling it quite right; I may be partially interpreting it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-Surprise #1:&lt;/strong&gt;  Prolog is slow!  Even still, it didn't do &lt;em&gt;that&lt;/em&gt; poorly.  (The 3.07 on the first run seems to be a bit of an outlier.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Surprise #3:&lt;/strong&gt; Python. The first execution with new code, it
runs a bit slow. But then it greatly improves every time after! If I clobber
all non-source in the Python folder, it goes back to a slow execution followed
by much faster executions. Python is dropping a &lt;code&gt;problem004.pyc&lt;/code&gt;
next to my original &lt;code&gt;problem004.py&lt;/code&gt;, and I assume that it's some
byte code. Unlike Haskell and Erlang, Python's compilation time is being held
against it, and it that light it makes its first run a bit more
impressive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Surprise #4:&lt;/strong&gt; Ruby sucks!  Well, not really.  Its performance on this one particular task isn't that good, but then I never expected it to be.  On the other hand, I didn't expect it to be this bad.  You'll notice that I have the running time for Ruby 1.9 as well.  I've read that Ruby 1.9 is supposed to be making some serious performance improvements, and my numbers here seem to bear this out.&lt;/p&gt;

&lt;h4&gt;More Analysis of the Ruby Performance&lt;/h4&gt;

&lt;p&gt;There is something unfair about the Ruby and Prolog code.  I used built-in list comprehensions in the other languages, and those languages can (and should) optimize them.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://jdfrens.blogspot.com/2008/12/pe-problem-4-in-all-languages.html"&gt;code I posted previously&lt;/a&gt; is, I feel a more syntactically honest transliteration of the list comprehension into Ruby.  But originally I wrote my Ruby solution with the palindrome assertion &lt;em&gt;and&lt;/em&gt; maximum search &lt;em&gt;in the body of nested loops&lt;/em&gt;.  That did much better:&lt;/p&gt;

&lt;table summary="running time" border="1"&gt;
 &lt;tr&gt;&lt;th rowspan="2"&gt;Language&lt;/th&gt;&lt;th colspan="3"&gt;Run/Running Time (in seconds)&lt;/th&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;th&gt;1st&lt;/th&gt;&lt;th&gt;2nd&lt;/th&gt;&lt;th&gt;3rd&lt;/th&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Ruby&lt;/td&gt;   &lt;td&gt;1.89&lt;/td&gt;&lt;td&gt;1.87&lt;/td&gt;&lt;td&gt;1.87&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;Ruby 1.9&lt;/td&gt;&lt;td&gt;1.03&lt;/td&gt;&lt;td&gt;0.98&lt;/td&gt;&lt;td&gt;0.95&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;From a "what gets executed" standpoint, this version of the Ruby code is probably closer to what the other languages compute.  And of course this should be much faster since it doesn't have to remember on the order of 10000 products in a list!  Now granted, Haskell, Erlang, and Python will have to remember all of the palindromes before it can compute the maximum, but that's still a pretty significant difference.&lt;/p&gt;

&lt;p&gt;I don't see how to get Prolog to a more efficient list-comprehension level, but this must be because I'm just not in the Prolog groove yet.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5288880965096658213?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5288880965096658213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5288880965096658213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5288880965096658213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5288880965096658213'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/12/language-performance-on-pe-problem-4.html' title='Language Performance on PE Problem #4'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-338396243645427590</id><published>2008-12-20T17:01:00.003-05:00</published><updated>2008-12-24T17:10:22.779-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><title type='text'>State of my Mac</title><content type='html'>&lt;p&gt;Just an update on my MacBook. Previously, it looked like &lt;a
href="http://jdfrens.blogspot.com/2008/06/languages-and-system-for-project-euler.html"&gt;this&lt;/a&gt;.
Here are its stats now:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Mac OS X 10.5.6&lt;/li&gt;
    &lt;li&gt;2 GHz Intel Core 2 Duo&lt;/li&gt;
    &lt;li&gt;2 GB 667 MHz DDR2 SDRAM&lt;/li&gt;
&lt;/ul&gt;        

&lt;ul&gt;
    &lt;li&gt;MacPorts version 1.7&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
    &lt;li&gt;Official Erlang version R12B-5&lt;/li&gt;
    &lt;li&gt;Glasgow Haskell Compiler version 6.10.1&lt;/li&gt;
    &lt;li&gt;SWI-Prolog version 5.6.63&lt;/li&gt;
    &lt;li&gt;Official Python version 2.6.1&lt;/li&gt;
    &lt;li&gt;Official Ruby (MRI) version 1.8.7&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All languages come from MacPorts now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; added a title.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-338396243645427590?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/338396243645427590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=338396243645427590' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/338396243645427590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/338396243645427590'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/12/just-update-on-my-macbook.html' title='State of my Mac'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4453792803373254417</id><published>2008-12-19T13:27:00.000-05:00</published><updated>2008-12-19T15:48:18.839-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><category scheme='http://www.blogger.com/atom/ns#' term='prolog'/><title type='text'>PE Problem #4 in All Languages</title><content type='html'>&lt;h4&gt;The Problem&lt;/h4&gt;

&lt;p&gt;Problem #4 is to find the largest palindrome that is the product of two
three-digit numbers. You just need to come out with the product itself, not
the factors.&lt;/p&gt;

&lt;p&gt;I figured I'd go for the brute-force solution first: try every product
&lt;code&gt;x*y&lt;/code&gt; for &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; over the range 100
through 999. Grab the palindromes, and grab the maximum.&lt;/p&gt;

&lt;p&gt;I figured there must be a clever way to reduce the search space.  For example, I could just search where &lt;code&gt;x &amp;lt;= y&lt;/code&gt;.  But after I wrote my first version using the brute-force algorithm, it ran fast enough that I decided not to worry about it unless the programming language forced me.  In the end, I implemented this brute-force algorithm in all five languages.&lt;/p&gt;

&lt;p&gt;This blog entry turned out a little longer than I had intended, so I'm breaking it up into two different pieces.  This entry will talk about my solution to the problem; the next entry will talk about some timing tests that I ran.&lt;/p&gt;

&lt;h4&gt;Recognizing a Palindrome&lt;/h4&gt;

&lt;p&gt;For some reason, I was not eager to write a divide-and-modulus algorithm to numerically determine if I had a palindrome.  I went with a conversion solution: convert the number into a string, reverse the string, compare with the original string.&lt;/p&gt;

&lt;p&gt;Even though I knew basically what I was searching for in the documentation, I found myself stuck a few times.  But in the end, each of my languages had an "integer to string" conversion and a "reverse this string/list" function.  Two of them were particularly surprising.&lt;/p&gt;

&lt;p&gt;Python's solution has some wacky syntax: &lt;code&gt;`n`[::-1]&lt;/code&gt;.  The backticks convert a number into a string.  (This is kind of ugly and definitely non-intuitive.)  The wacky index operator &lt;code&gt;[::-1]&lt;/code&gt; &lt;em&gt;reverses the string&lt;/em&gt;.  Without reading the documentation too deeply, I figure &lt;code&gt;[n:m:s]&lt;/code&gt; would normally return a substring of the original.  By leaving the first two arguments empty, it's assumed that I want the two ends of the string, and the &lt;code&gt;-1&lt;/code&gt; indicates "traverse this substring backwards".&lt;/p&gt;

&lt;p&gt;The Prolog solution surprised me, but it shouldn't have. Prolog is a logic
language, and so the whole idea of "is Reverse the same as Original?" is built
into the language:&lt;/p&gt;

&lt;pre&gt;
is_palindrome(N) :- name(N, S), reverse(S, S).
&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;name&lt;/code&gt; turns an integer into a string (or a
string into an integer). The wacky bit is &lt;code&gt;reverse(S,S)&lt;/code&gt;; unlike the other languages, there's no explicit equality test.  This is because Prolog is &lt;em&gt;always&lt;/em&gt; asking, "How can I logically satisfy these constraints?".  Underlying "satisfaction" is the idea of equality, and what Prolog has to do to achieve satisfaction depends on what data and what variables are passed in.&lt;/p&gt;

&lt;p&gt;Let's consider two calls to &lt;code&gt;reverse&lt;/code&gt;.  &lt;code&gt;reverse([1, 2, 3], R)&lt;/code&gt; is satisfied by &lt;code&gt;R = [3, 2, 1]&lt;/code&gt;, and &lt;code&gt;reverse(S, [3, 2, 1])&lt;/code&gt; is satisfied by &lt;code&gt;S = [1, 2, 3]&lt;/code&gt;.  (It helps if you &lt;em&gt;don't&lt;/em&gt; think about how Prolog might do this; just go with your intuition on the logic here: what does &lt;code&gt;R&lt;/code&gt; or &lt;code&gt;S&lt;/code&gt; need to be to satisfy the logic?)&lt;/p&gt;

&lt;p&gt;No matter how we ask to have &lt;code&gt;reverse&lt;/code&gt; satisfied, Prolog will figure out if and how it's possible.  So a call like &lt;code&gt;reverse([1,2,3], [3,2,1])&lt;/code&gt; is just simply &lt;code&gt;true&lt;/code&gt;; similarly &lt;code&gt;reverse([1, 2, 3], [1, 2, 3])&lt;/code&gt; is always &lt;code&gt;false&lt;/code&gt;.  Neither expression has free variables that have to be set in order to find satisfaction; Prolog just has to make sure it's consistent.  This is the situation we have in &lt;code&gt;is_palindrome(N)&lt;/code&gt;, &lt;code&gt;S&lt;/code&gt; is bound by the &lt;code&gt;name(N,S)&lt;/code&gt; expression, so &lt;code&gt;reverse(S,S)&lt;/code&gt; is there to give a true/false result.&lt;/p&gt;

&lt;p&gt;(Incidentally, just evaluating &lt;code&gt;reverse(S, R)&lt;/code&gt; does return something; in fact, it returns a lot of somethings!  But I've already strayed away from my Project Euler problem.  It's worth investigating, though, once you get into Prolog.)


&lt;h4&gt;Searching the Products for a Palindrome&lt;/h4&gt;

&lt;p&gt;Haskell once again provides the tightest solution:&lt;/p&gt;

&lt;pre&gt;
findPalindromeProduct n =
  maximum [x * y | x &amp;lt;- range, y &amp;lt;- range, isPalindrome (x * y)]
    where range = [n..(n*10-1)]
&lt;/pre&gt;

&lt;p&gt;Erlang and Python also have list comprehensions, and their solutions look quite similar.  If you squint a bit, the Prolog version looks like a list comprehension.  Ruby, though, forced me to make the loops explicit:&lt;/p&gt;

&lt;pre&gt;
class Integer
  def find_palindrome_product
    products.select { |p| p.palindrome? }.max
  end

  def products
    products = []
    (self..(self*10-1)).each do |x|
      (self..(self*10-1)).each do |y|
        products &amp;lt;&amp;lt; (x * y)
      end
    end
    products
  end
end
&lt;/pre&gt;

&lt;p&gt;I really don't like the &lt;code&gt;products&lt;/code&gt; method.  A method like &lt;code&gt;Enumerable#zip()&lt;/code&gt; will traverse multiple lists in lock step; I need a &lt;a href="http://en.wikipedia.org/wiki/Cartesian_product"&gt;Cartesian-product&lt;/a&gt; kind of traversal.  But this does provided a list-comprehension like feel (as good as it'll get in Ruby).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4453792803373254417?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4453792803373254417/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4453792803373254417' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4453792803373254417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4453792803373254417'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/12/pe-problem-4-in-all-languages.html' title='PE Problem #4 in All Languages'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4013920308502861684</id><published>2008-12-14T18:21:00.002-05:00</published><updated>2008-12-14T19:17:45.340-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><title type='text'>PE Problem #3 in All Languages</title><content type='html'>&lt;p&gt;Wow.  It's been a &lt;em&gt;very&lt;/em&gt; long time since I blogged here.  It's been even longer since I worked on a &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; problem.  But rather than start on the large pile of grading I need to do at the end of the semester, I decided to work on Problem #3.&lt;/p&gt;

&lt;h4&gt;The Problem&lt;/h4&gt;

&lt;p&gt;Problem #3 is to find the largest prime factor of a number.  To get myself into the flow of things again, I started with a Haskell solution because I knew that Haskell's lazy evaluation makes a prime number list interesting and fun to write.&lt;/p&gt;

&lt;h4&gt;The Haskell Solution (and Erlang)&lt;/h4&gt;

&lt;p&gt;Let me jump to my punch line: &lt;em&gt;you don't need to calculate any prime numbers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's my Haskell solution:&lt;/p&gt;

&lt;pre&gt;
gpfSearch f x | x == f      = x
              | divides x f = gpfSearch f (div x f)
              | otherwise   = gpfSearch (f+1) x
  where divides x y = mod x y == 0
&lt;/pre&gt;

&lt;p&gt;I start this "search" at &lt;code&gt;f=2&lt;/code&gt;, and as factors are found, they are factored out.  Since each prime number is smaller than it's multiples, I only ever factor out prime numbers.  (E.g., &lt;code&gt;f=16&lt;/code&gt; &lt;em&gt;never&lt;/em&gt; divides &lt;code&gt;x&lt;/code&gt; because even if 16 is a factor, &lt;code&gt;f=2&lt;/code&gt; would be factored out four times.)  So by the time I factor the original number down to &lt;code&gt;x==f&lt;/code&gt;, the number must be a prime factor and the largest.&lt;/p&gt;

&lt;p&gt;The question on the Project Euler site forces you to use bigints, so I discovered the difference between Haskell's &lt;code&gt;Int&lt;/code&gt; and &lt;code&gt;Integer&lt;/code&gt; types (i.e., machine int and bigint, respectively).&lt;/p&gt;

&lt;p&gt;Since this version ran as fast as my compute-primes-and-factor-with-them-only version, I tossed my prime-number code.  Since my code takes about a quarter of a second to find the greatest prime factor of a 12-digit number, the simpler code wins.  (On the other hand, looking forward to some of the future Project Euler problems, I probably should have kept it in a separate library.)&lt;/p&gt;

&lt;p&gt;My Erlang solution was similar, just with a different syntax.&lt;/p&gt;

&lt;h4&gt;The Python Solution (and Ruby)&lt;/h4&gt;

&lt;p&gt;Erlang was actually my third language with this problem.  My second language was Python, and I discovered a whole new problem that Haskell and Erlang fixed for me automatically: tail recursion.&lt;/p&gt;

&lt;p&gt;Consider this: &lt;code&gt;gpfSearch 2 n&lt;/code&gt; will try out (at worst) &lt;code&gt;sqrt(n)&lt;/code&gt; different factors.  The square root of a 12-digit number will be a 6-digit number.   That's an awfully tall runtime stack!  However, &lt;code&gt;gpfSearch&lt;/code&gt; is &lt;strong&gt;tail recursive&lt;/strong&gt;.  I've talked about tail recursion before on this blog, so in a nutshell: since &lt;code&gt;gpfSearch&lt;/code&gt; calls itself recursively as the last thing to do in each case, the function can be turned into a loop.  And this is what Haskell and Erlang do, since they optimize tail recursion.&lt;/p&gt;

&lt;p&gt;Python does not.  So it runs out of stack space and whines.&lt;/p&gt;

&lt;p&gt;I ended up with this solution:&lt;/p&gt;

&lt;pre&gt;
def gpfSearch(n, f):
  while n != f:
    if divides(n, f):
      n = n / f
    else:
      f = f + 1
  return f
&lt;/pre&gt;

&lt;p&gt;This &lt;em&gt;is&lt;/em&gt; the code executed by Haskell and Erlang; I just have to do the optimization by hand in Python.&lt;/p&gt;

&lt;p&gt;And in Ruby.&lt;/p&gt;

&lt;p&gt;I'm struck by how much easier it is to read and understand the Haskell/Erlang solutions.  The loop does not seem intuitive to me at all &lt;em&gt;unless you start with the recursive version in your head&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;The Prolog Solution&lt;/h4&gt;

&lt;p&gt;Once again, I got a bit frustrated with Prolog.  And, again, I feel a bit bad about it because arithmetic is just not its thing.  (I mean, there's a &lt;em&gt;really&lt;/em&gt; good reason why I'm not doing these problems in SQL!)&lt;/p&gt;

&lt;p&gt;I thought a compute-primes-first solution might actually work out better in Prolog:&lt;/p&gt;

&lt;pre&gt;
greatest_prime_factor1(N, P) :-
  gpf_search(N, Factors), max_list(Factors, P).

gpf_search(N, Factors) :-
  N2 is ceil(sqrt(N)),
  primes2(N2, Primes),
  include(divides(N), Primes, Factors).
&lt;/pre&gt;

&lt;p&gt;This gives the right answer, but it blows up on the 12-digit number.  It also takes a long time to blow up.  (Python and Ruby blew up very quickly with the recursive definitions.)  The problem is with my &lt;code&gt;primes2(N, Ps)&lt;/code&gt; predicate; when the Project Euler problems require that I actually compute prime numbers, I'll come back to this.&lt;/p&gt;

&lt;p&gt;To get a version that works with the 12-digit number, I transliterated &lt;code&gt;gpfSearch&lt;/code&gt; from Haskell.  Since Prolog also optimizes tail recursion, the recursion over the large number isn't a problem.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4013920308502861684?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4013920308502861684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4013920308502861684' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4013920308502861684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4013920308502861684'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/12/pe-problem-3-in-all-languages.html' title='PE Problem #3 in All Languages'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-2472239925345919405</id><published>2008-08-30T20:24:00.002-04:00</published><updated>2008-08-30T20:26:07.583-04:00</updated><title type='text'>I've started a second blog!</title><content type='html'>&lt;p&gt;'Cause I just didn't have enough to do:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://compilerclub.blogspot.com/"&gt;Compiler Club&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three guesses what the new blog is about; first two don't count.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-2472239925345919405?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/2472239925345919405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=2472239925345919405' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2472239925345919405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/2472239925345919405'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/08/ive-started-second-blog.html' title='I&apos;ve started a second blog!'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4456527764113239569</id><published>2008-08-25T15:35:00.003-04:00</published><updated>2008-08-25T15:43:46.104-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dependency injection'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>Dependency Injection with Guice</title><content type='html'>&lt;p&gt;I've been looking for a good tutorial on how to use &lt;a href="http://code.google.com/p/google-guice/"&gt;Google Guice&lt;/a&gt; for dependency injection.  I've been doing dependency injection by hand for a couple years now, but Guice crossed my radar recently, and I desperately needed to learn something new.  (I mean, it would be a shame to start preparing for the fall semester a whole two weeks before it started!)&lt;/p&gt;

&lt;p&gt;For some reason, the Guice User Guide wasn't that useful to me.  I'm sure the necessary information I need is in there, but I couldn't (mentally) put together a complete example from it.  A Google search revealed &lt;a href="http://www.factorypattern.com/google-guice-tutorial/"&gt;this tutorial&lt;/a&gt;.  Very useful!&lt;/p&gt;

&lt;p&gt;I also came across this &lt;a href="http://video.google.com/videoplay?docid=6068447410873108038"&gt;Google Talk&lt;/a&gt;.  I can't comment on it yet because I'm about to watch it now.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4456527764113239569?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4456527764113239569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4456527764113239569' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4456527764113239569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4456527764113239569'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/08/dependency-injection-with-guice.html' title='Dependency Injection with Guice'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1511283895604202254</id><published>2008-08-22T09:50:00.001-04:00</published><updated>2008-08-22T09:53:50.377-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='silly'/><title type='text'>Just in case you were wondering...</title><content type='html'>&lt;p&gt;&lt;a href="http://www.oneplusyou.com/q/v/space_vacuum"&gt;&lt;img border="0" src="http://www.oneplusyou.com/q/img/badges/space_vacuum_1_minute_29_seconds.jpg" alt="How long could you survive in the vacuum of space?" /&gt;&lt;/a&gt;&lt;br /&gt;Created by OnePlusYou - &lt;a href="http://www.oneplusyou.com"&gt;Online Dating&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quite frankly, I don't believe it.  &lt;a href="http://www.oneplusyou.com/q/v/space_vacuum"&gt;Try it yourself.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1511283895604202254?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1511283895604202254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1511283895604202254' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1511283895604202254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1511283895604202254'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/08/just-in-case-you-were-wondering.html' title='Just in case you were wondering...'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5081653465449926780</id><published>2008-08-11T11:49:00.002-04:00</published><updated>2008-08-11T12:54:34.547-04:00</updated><title type='text'>Literate Programming</title><content type='html'>&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Literate_programming"&gt;Literate programming&lt;/a&gt; is an interesting phenomenon. I bought it to it strongly back
in the 1990s. I wrote an entire technical report (&lt;a href="http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR433"&gt;"Matrix
Inversion using Quadtrees Implemented in Gofer"&lt;/a&gt;) using &lt;a href="http://www.cs.tufts.edu/~nr/noweb/"&gt;Noweb&lt;/a&gt;; I also used it for writing the
code for my dissertation.  In hindsight, I used Noweb as a strange macro system for my dissertation code ("strange" as in "not effective").&lt;/p&gt;

&lt;p&gt;What intrigues me most about literate programming now (and then) is the technical
side of it. How does one turn a literate document into code and into a printable
document? Sure, it's just a variation on interpreting and compiling, but I love those
topics, too.&lt;/p&gt;

&lt;p&gt;As a tool for writing code, I'm much less keen on it. It still has the drawback of
keeping the comments in line with the code, and that's a &lt;em&gt;huge&lt;/em&gt; drawback. I
did find myself more willing to write comments and keep them maintained with literate
programming; I attribute this to the expressiveness of LaTeX (especially when it
comes to mathematics).&lt;/p&gt;

&lt;p&gt;Two things killed literate programming for me. First, Donald Knuth (the father of
literate programming) &lt;a href="http://www.informit.com/articles/article.aspx?p=1193856"&gt;bad mouthed unit
testing and mock objects&lt;/a&gt;. How could I possibly take anything he says seriously?!
No, seriously, that's not any reason at all. But some of you were thinking it of
me... Knuth, just like anyone else, is welcome to his own wrong opinions.&lt;/p&gt;

&lt;p&gt;Actually first, IDE support. Once I used &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; for a couple of hours, I gave up emacs and
never looked back (at least for writing Java). emacs had minimal literate programming
support; Eclipse had none. But the features I gained with Eclipse are worth anything
I lost.&lt;/p&gt;

&lt;p&gt;Second, unit tests and TDD. "Literate comments" are supposed to serve the same
purpose as unit tests and TDD: drive the design. Unlike literate comments, though,
unit tests can be executed to verify that your code matches your design. Then they
serve as regression tests. You &lt;em&gt;have&lt;/em&gt; to keep the unit tests up-to-date.
Literate comments sit there and require a human to read them; they don't check your
work; they don't stay up to date on their own.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5081653465449926780?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5081653465449926780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5081653465449926780' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5081653465449926780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5081653465449926780'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/08/literate-programming.html' title='Literate Programming'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5898113259055156512</id><published>2008-08-10T19:24:00.005-04:00</published><updated>2010-01-22T15:56:59.959-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='null'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>Returning 'null' considered EVIL!</title><content type='html'>&lt;p&gt;I came across this article tonight: &lt;a href="http://andyp-tw.blogspot.com/2008/08/returning-null-considered-dishonest.html"&gt;"Returning 'null' Considered Dishonest"&lt;/a&gt; by Andy P.  I'm with you all the way, Andy, except that I'll go so far as to say that returning &lt;code&gt;null&lt;/code&gt; is evil.  I hate it.&lt;/p&gt;

&lt;p&gt;Read Andy's article for a more rational, calmer analysis of the issues.  I would just add that the &lt;a href="http://en.wikipedia.org/wiki/Null_object"&gt;Null Object pattern&lt;/a&gt; has worked very well for me in the past.&lt;/p&gt;

&lt;p&gt;And now I see a link between Null Objects and &lt;a href="http://en.wikipedia.org/wiki/Monad_(functional_programming)"&gt;monads&lt;/a&gt; has opened up to me.  Yikes!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5898113259055156512?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5898113259055156512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5898113259055156512' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5898113259055156512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5898113259055156512'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/08/returning-null-considered-evil.html' title='Returning &apos;null&apos; considered EVIL!'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-6483227662457481658</id><published>2008-07-28T12:23:00.003-04:00</published><updated>2008-07-28T13:05:54.222-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>No side effects!</title><content type='html'>&lt;p&gt;Kevin Smith (the Erlang programmer, not the director) has a post up today on his blog &lt;i&gt;Hypothetical Labs&lt;/i&gt; about &lt;a href="http://weblog.hypotheticalabs.com/?p=281"&gt;"Erlang &amp;amp; Single Assignment: You’re Doing It Wrong"&lt;/a&gt;.  I got trained in grad school to program without side effects, and now I consciously avoid them like the plague (some hyperbole thrown in for the fun of it).&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;real&lt;/em&gt; point of his article (in my mind) is to &lt;em&gt;use the paradigm and features of your programming language&lt;/em&gt;.  For my Project Euler solutions, I've been happy to use list comprehensions in Haskell and Python; I use &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;select&lt;/code&gt; in Ruby since that's what it supports (not list comprehensions).  My purpose for working on Project Euler with multiple languages has been to learn the features and paradigms of each specific language.&lt;/p&gt;

&lt;p&gt;On the other hand, it's important to see how to implement a feature from one language in another.  Some feature translations are easier than others, and some can be really, really powerful.  I missed out on one of these opportunities on the second Project Euler problem which required &lt;a href="http://jdfrens.blogspot.com/2008/07/pe-problem-2-in-all-languages-part-ii.html"&gt;computing Fibonacci numbers&lt;/a&gt;.  Haskell allowed me to construct an infinite list which I could take off just the values that I wanted.  In the other languages, I wrote a combination take-what-I-want and compute-Fibonacci-numbers recursive function.  What I should have tried was to write a &lt;a href="http://en.wikipedia.org/wiki/Coroutines"&gt;coroutine&lt;/a&gt; (e.g., &lt;a href="http://pragdave.blogs.pragprog.com/pragdave/2007/12/pipelines-using.html"&gt;Fiber&lt;/a&gt; in Ruby 1.9).&lt;/p&gt;

&lt;p&gt;Read Smith's article.  It's short and has some good specific observations.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-6483227662457481658?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/6483227662457481658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=6483227662457481658' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6483227662457481658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6483227662457481658'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/no-side-effects.html' title='No side effects!'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7046009581884745886</id><published>2008-07-25T12:32:00.004-04:00</published><updated>2008-07-25T14:05:34.251-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='programming style'/><title type='text'>/* No Comment */</title><content type='html'>&lt;p&gt;I've been working this week mostly on an acceptance-test system for compilers and interpreters.  It's coming along well, but it means learning a few new things about &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; and a &lt;em&gt;lot&lt;/em&gt; of new things about &lt;a href="http://git.or.cz/"&gt;git&lt;/a&gt;.  I also had to spend time with &lt;a href="http://flickr.com/photos/jdfrens/2698685781/"&gt;my new toy&lt;/a&gt;.  (Yeah, that picture scares me, too.)&lt;/p&gt;

&lt;h4&gt;Commenting on Not Commenting&lt;/h4&gt;

&lt;p&gt;As I was reading my blogs this morning, I can across an &lt;em&gt;excellent&lt;/em&gt; post about &lt;em&gt;not&lt;/em&gt; commenting code: &lt;a href="http://www.codinghorror.com/blog/archives/001150.html"&gt;Coding Without Comments&lt;/a&gt; by Jeff Atwood at &lt;a href="http://www.codinghorror.com/"&gt;Coding Horror&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Jeff gets at the heart of the matter: "the code already tells us &lt;em&gt;how&lt;/em&gt; it works; we need comments to tell &lt;em&gt;why&lt;/em&gt; it works" (emphasis his and mine).  But even then, comments are the wimp's way out.  Jeff goes on to say: "While comments are neither inherently good or bad, they are frequently used as a crutch. &lt;strong&gt;You should always write your code as if comments didn't exist.&lt;/strong&gt;" (emphasis his and mine)  Refactoring is a very powerful tool, and for the clarity that Renaming and Extracting refactorings give us, it's insane not to do it early and often.&lt;/p&gt;



&lt;h4&gt;When to Comment&lt;/h4&gt;

&lt;p&gt;Never.&lt;/p&gt;

&lt;p&gt;Sorry.  That's too flip, but it will tick off the right people.&lt;/p&gt;

&lt;p&gt;Jeff links to &lt;a href="http://www.codeodor.com/index.cfm/2008/6/18/Common-Excuses-Used-To-Comment-Code-and-What-To-Do-About-Them/2293"&gt;"Common Excuses Used to Comment and What to Do About Them"&lt;/a&gt; by Sammy Larbi at his wonderfully named blog "My Secret Life as a Spaghetti Coder".  He lists some great objections with some greater rebuttals.&lt;/p&gt;

&lt;p&gt;Sam lists four valid reasons for writing comments: Javadocs, truly complex code, TODOs, and design decisions (when the obvious implementation isn't used).  I agree with all of these exceptions as long as they are &lt;em&gt;truly&lt;/em&gt; exceptional.&lt;/p&gt;

&lt;p&gt;For example, I wrote &lt;a href="http://antlr-testing.sourceforge.net/doc/index.html"&gt;complete Javadocs&lt;/a&gt; for my &lt;a href="http://antlr-testing.sourceforge.net/"&gt;ANTLR Testing library&lt;/a&gt;.  It's a Java library for public consumption, and a library is code &lt;em&gt;and&lt;/em&gt; documentation.  (Libraries used internally can rely on unit tests for API documentation.)  On the other hand, my &lt;a href="http://nolatte.sourceforge.net/"&gt;No Latte interpreter&lt;/a&gt; has little to no Javadocs because it's primarily an executable system, not a plug-in library.&lt;/p&gt;

&lt;p&gt;Complex code and non-obvious design decisions really don't come up that often.  Certainly there's a lot of variance on this, and I'd expect embedded-system developers to say it comes up all the time.  Perhaps.  But considering how rapidly technology improves, stay vigilant!  You might be able to simplify some code that "had" to be complex two years ago.&lt;/p&gt;

&lt;h4&gt;Other Articles&lt;/h4&gt;

&lt;p&gt;Sam links to two other articles: &lt;a href="http://www.briankotek.com/blog/index.cfm/2008/6/5/Dont-Comment-Your-Code"&gt;"Don't Comment Your Code"&lt;/a&gt; by Brian Kotek and &lt;a href="http://www.bennadel.com/index.cfm?dax=blog:1255.view"&gt;"Not Commenting And The Tipping Point Of Poor Programming"&lt;/a&gt; by Ben Nadel.  (Ben's post was based on Brian's.)&lt;/p&gt;

&lt;p&gt;Brian's post is pretty good, but basic.  I can see how he started this whole web of articles started.  (And, of course, he didn't start it himself, but I'm only going to go two generations back in this web.  Read his article to follow the web further yourself.)&lt;/p&gt;

&lt;p&gt;Ben's post is really interesting because he's actually in favor of comments.  The basic argument Ben lays out is that gurus saying "don't comment" will give license to beginners to not comment.  There are &lt;em&gt;so&lt;/em&gt; many things wrong with this.&lt;p&gt;

&lt;p&gt;First, I don't mind comments as a temporary stand-in for code.  It &lt;em&gt;can&lt;/em&gt; help to articulate an algorithm in a natural language first (I usually pick Latin).  But &lt;em&gt;replace&lt;/em&gt; the comments with real code.  Each time I do something like this, the code is a succinct expression of the natural-language description.&lt;/p&gt;

&lt;p&gt;Second, what makes anyone think that someone who can't program can write a good comment?  I've found a direct correlation between code and comments; as the quality of one declines, so does the other.&lt;/p&gt;

&lt;p&gt;Third, why would anyone want to teach a programmer that writing a comment is a good way to cover up bad code?  We need to teach them to be good programmers who write good code.  And this isn't just those of us in academia; it's your responsibility to teach your co-workers.&lt;/p&gt;


&lt;h4&gt;Teaching to Not Comment&lt;/h4&gt;

&lt;p&gt;The issue of comments in my classes is one I've struggled with.  Javadoc is a valuable technology which my students need to know, so I've required it in the intro courses I've taught.  (Although I haven't always been as strict with grading it as I should have.)&lt;/p&gt;

&lt;p&gt;I'm beginning to see the value in doing code reviews in class.  In a data-structures-and-algorithms class I taught a few years ago, I noticed that the top students in the class tended to write rather lengthy methods broken into chunks (separated by whitespace), and at the beginning of each chunk was a comment perfectly describing the "why" of the next chunk.  It just &lt;em&gt;screamed&lt;/em&gt; to me: Extract Method!!!  The comment becomes the name of the method, and the code becomes self documenting.  Since Eclipse (or any decent IDE) has the ability to do the refactoring for you, it becomes a no brainer!  A code review or two would have been useful for all students to see the better way to write their code.&lt;/p&gt;

&lt;p&gt;Unfortunately, all programmers tend to be fairly embarrassed about their code, so it might be difficult to get permission to do this in a large class.&lt;/p&gt;

&lt;p&gt;There's also a need to have students &lt;em&gt;read&lt;/em&gt; more code.  We don't teach students how to write English essays by requiring them to write all of the time; we also have them read a lot.  The same should be true about code (although maybe not in the same proportions).  By reading more code, they get to see at least what does and doesn't work for them.&lt;/p&gt;

&lt;h4&gt;Buy a T-Shirt&lt;/h4&gt;

&lt;p&gt;The name of the post comes from &lt;a href="http://www.thinkgeek.com/tshirts/generic/76aa/"&gt;my favorite t-shirt&lt;/a&gt; at &lt;a href="http://www.thinkgeek.com/"&gt;ThinkGeek&lt;/a&gt;.  Buy one for each member of your family.  Get the word out.  Get the comments out!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7046009581884745886?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7046009581884745886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7046009581884745886' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7046009581884745886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7046009581884745886'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/no-comment.html' title='/* No Comment */'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5670218511662393710</id><published>2008-07-21T18:30:00.002-04:00</published><updated>2008-07-21T18:48:26.519-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='programming style'/><title type='text'>Use punctution?</title><content type='html'>&lt;p&gt;Ryan Bates, in his &lt;a href="http://railscasts.com/episodes/119"&gt;latest episode&lt;/a&gt; of the freakin' awesome &lt;a href="http://railscasts.com/"&gt;Railscasts&lt;/a&gt;, defines a function with this name:&lt;/p&gt;

&lt;pre&gt;def can_edit_comment?(comment)&lt;/pre&gt;

&lt;p&gt;Seeing this after my last post here, I started wondering if the &lt;code&gt;can_&lt;/code&gt; prefix is necessary or should I get whiny about it, too?  &lt;code&gt;edit_comment?&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; sufficient and certainly succinct, but I'm not so convinced that I feel the need to get whiny.&lt;/p&gt;

&lt;p&gt;Strangely, though, I'm more in favor of &lt;code&gt;editable_comment?&lt;/code&gt;.  To me it's clearer, although it has the same number of characters as the original.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then&lt;/em&gt; I started wondering about &lt;code&gt;_comment&lt;/code&gt;!  If this were Java or some other language with overloading and compile-time typing, then I'd leave that &lt;code&gt;_comment&lt;/code&gt; off: &lt;code&gt;editable?&lt;/code&gt;.  I'd let the type system prevent me from passing in the wrong kind of object.  But in Ruby, with duck typing, that &lt;code&gt;_comment&lt;/code&gt; adds a little bit of protection for me, but not so much that I feel whiny about it.&lt;/p&gt;

&lt;p&gt;Hopefully, I'll have some less whiny posts for the rest of this week...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5670218511662393710?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5670218511662393710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5670218511662393710' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5670218511662393710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5670218511662393710'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/use-punctution_21.html' title='Use punctution?'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-6233640315028293918</id><published>2008-07-21T12:33:00.003-04:00</published><updated>2008-07-21T12:53:16.724-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='programming style'/><title type='text'>Use punctution!</title><content type='html'>&lt;p&gt;I'm presently reading over an IBM DeveloperWork's article &lt;a href="http://www.ibm.com/developerworks/opensource/library/os-eclipse-iphoneruby1/"&gt;"Developing iPhone applications using Ruby on Rails and Eclipse, Part 1: Serving content for iPhones"&lt;/a&gt;.  I'm trying to find out how are it is to optimize a website for an iPhone.&lt;/p&gt;

&lt;p&gt;In the article, I came across this Ruby code:&lt;/p&gt;

&lt;pre&gt;
def is_iphone_request?
  request.user_agent =~ /(Mobile\/.+Safari)/
end
&lt;/pre&gt;

&lt;p&gt;Question: anything strike you as odd?&lt;/p&gt;

&lt;p&gt;Hint: there's a redundancy.&lt;/p&gt;

&lt;p&gt;Answer: why is the method named with a &lt;code&gt;is_&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; a &lt;code&gt;?&lt;/code&gt; suffix?  The &lt;code&gt;?&lt;/code&gt; is a &lt;em&gt;wonderful&lt;/em&gt; character to succinctly and &lt;em&gt;clearly&lt;/em&gt; indicate the question posed by the method&amp;mdash;better than &lt;code&gt;is_&lt;/code&gt; ever could.&lt;/p&gt;

&lt;p&gt;I've done this myself, usually after coding in Java for a while, so I harbor no ill feelings towards the author of the code.  But names &lt;em&gt;really&lt;/em&gt; matter.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-6233640315028293918?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/6233640315028293918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=6233640315028293918' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6233640315028293918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/6233640315028293918'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/use-punctution.html' title='Use punctution!'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-4295011433080390351</id><published>2008-07-15T11:05:00.002-04:00</published><updated>2008-07-15T11:10:16.013-04:00</updated><title type='text'>BarCamp Grand Rapids</title><content type='html'>&lt;p&gt;I'm guessing that anyone reading this blog in the Grand Rapids (Michigan) area already knows about &lt;a href="http://barcampgr.org/"&gt;BarCamp Grand Rapids&lt;/a&gt;, but it won't hurt for me to advertise.  Here's an ad written by Kyle Adams, one of the organizers of BarCamp Grand Rapids:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;BarCamp Grand Rapids, inspired by the Silicon Valley event that rocked the emerging technology world with its audacity and success, will take place on August 15-16 at Calvin College.&lt;/p&gt;

&lt;p&gt;The original Palo Alto BarCamp was born out of frustration with the stifling atmosphere of most conferences. In a bold move, the founders decided to hold an "unconference" and let the attendees decide the schedule and topics to be presented. The organizers provided only a venue, a blank schedule board, and some overhead projectors: attendees were responsible for creating all the content, giving all the presentations, and having all the fun. The experiment was a resounding success, and BarCamps in Toronto, Amsterdam, and New York City soon followed. BarCamp Grand Rapids continues this proud tradition, for the third year running.&lt;/p&gt;

&lt;p&gt;Calvin College is generously donating classroom space, including a space for a "campout" Friday night. Gordon Food Service, Subway, and Biggby Coffee will be providing food for the event, and SageTech will be hosting a get-together after the Friday night sessions. Elevator Up has also pitched in to help keep to conference free for all attendees.&lt;/p&gt;

&lt;p&gt;For the latest information and registration, see &lt;a href="http://barcampgr.org/"&gt;http://barcampgr.org/&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was a lot of fun last year, and I'm looking forward to this year's.  I even planned a vacation around it!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-4295011433080390351?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/4295011433080390351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=4295011433080390351' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4295011433080390351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/4295011433080390351'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/barcamp-grand-rapids.html' title='BarCamp Grand Rapids'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3048284967433738443</id><published>2008-07-12T13:33:00.003-04:00</published><updated>2008-07-12T13:38:38.324-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><title type='text'>Tail-recursive, linear-time Fibonacci in Haskell</title><content type='html'>&lt;p&gt;An article &lt;a href="http://www.iis.sinica.edu.tw/~scm/2008/tail-recursive-linear-time-fibonacci/"&gt;"Tail-Recursive, Linear-Time Fibonacci"&lt;/a&gt; by &lt;a href="http://www.iis.sinica.edu.tw/~scm/about/"&gt;Shin-Cheng Mu&lt;/a&gt; popped up in a Haskell blog this morning.  Looks like an interesting read.&lt;/p&gt;

&lt;p&gt;Read it now!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3048284967433738443?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3048284967433738443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3048284967433738443' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3048284967433738443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3048284967433738443'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/tail-recursive-linear-time-fibonacci-in.html' title='Tail-recursive, linear-time Fibonacci in Haskell'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-3006167804602216505</id><published>2008-07-11T19:32:00.002-04:00</published><updated>2008-07-11T19:35:18.932-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LISP'/><title type='text'>Henderson Escher</title><content type='html'>&lt;p&gt;A quick follow-up from my previous post.  If you'd like to see some code for the Henderson-Escher system, check out &lt;a href="http://bc.tech.coop/blog/050213.html"&gt;"Escher in LISP"&lt;/a&gt; from Bill Clementson.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-3006167804602216505?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/3006167804602216505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=3006167804602216505' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3006167804602216505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/3006167804602216505'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/henderson-escher.html' title='Henderson Escher'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7350850623867900180</id><published>2008-07-11T19:28:00.000-04:00</published><updated>2008-07-11T19:29:31.044-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='structure and interpretation of computer programs'/><title type='text'>Thinking Functionally</title><content type='html'>&lt;p&gt;Lecture 3a of &lt;a href="http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/"&gt;&lt;i&gt;Structure and Interpretation of Computer Programs&lt;/i&gt;&lt;/a&gt; is entitled "Henderson Escher Example".&lt;/p&gt;

&lt;p&gt;"Escher" refers to &lt;a href="http://en.wikipedia.org/wiki/Maurits_Cornelis_Escher"&gt;"M.C. Escher"&lt;/a&gt;, of course.  The "Henderson" refers to "Peter Henderson" who wrote an article, &lt;a href="http://www.ecs.soton.ac.uk/%7Eph/funcgeo.pdf"&gt;"Functional Geometry"&lt;/a&gt;,  which describes a beautiful system of functions that generate Escher-like pictures.&lt;/p&gt;

&lt;p&gt;Abelson and Susseman build up Henderson's system in LISP.  Unfortunately, they don't have the technology to actually do the drawing (it was 1986!), but the ideas are clearly there.&lt;/p&gt;

&lt;p&gt;I recently had a discussion with some friends about programming paradigms, and the idea of "it's how programmers/people think" came up.  One friend (are you reading this, Zach?) was pretty convinced that OOP wins this battle.  I know others who say the same thing for functional programming (John, you here?).  I won't argue this whole issue now (since they're &lt;em&gt;both&lt;/em&gt; right!), but this lecture puts forth a great argument that functional programming can clearly make the claim.&lt;/p&gt;

&lt;p&gt;The design of this system was based on &lt;em&gt;embedding&lt;/em&gt; the functional-geometry language &lt;em&gt;within&lt;/em&gt; LISP.  Abelson and Susseman first build up a library of basic objects: vectors (i.e., points) and line segments.  They're represented by lists, but that's all hidden by the constructors and accessors.  (Yes, OO fans, the functional people call them constructors and accessors, too!)&lt;/p&gt;

&lt;p&gt;On top of that level, Abelson and Susseman build picture and rectangle representations along with functions to scale, rotate, and combine pictures (within rectangles).  The result is amazingly elegant.&lt;/p&gt;

&lt;p&gt;Abelson and Susseman start waxing philosophical in these lectures, that this ability to embedded another language is one of LISP's greatest strengths.  By writing different layers of abstraction, it allows the programmer to change (or fix) functions at one level without having to deal with the other layers.  Abelson and Susseman take a few shots at up-front design (and the waterfall method) since one design decision early in the process cannot help but affect others; so when one decision has to change, later decisions have to adapt as well.  Yeah, LISP; boo, waterfall!&lt;/p&gt;

&lt;p&gt;You can decide if their attack on up-front design is fair (&lt;em&gt;after&lt;/em&gt; you watch the lectures).  This is also not to say that OO (or other paradigms) can't isolate layers of an application.  In fact, quite the contrary: OO uses private elements, module (package) systems, and design patterns to achieve the same results.  (I couldn't help but think about &lt;a href="http://en.wikipedia.org/wiki/Model_view_controller"&gt;model-view-controller&lt;/a&gt; and &lt;a href="http://rubyonrails.org"&gt;Ruby on Rails&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;highly&lt;/em&gt; recommend these lectures for those of you unfamiliar with the functional-programming paradigm.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7350850623867900180?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7350850623867900180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7350850623867900180' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7350850623867900180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7350850623867900180'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/thinking-functionally.html' title='Thinking Functionally'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5584124143442048700</id><published>2008-07-10T22:24:00.004-04:00</published><updated>2008-07-10T22:52:49.308-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='structure and interpretation of computer programs'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Structure and Interpretation of Computer Programs</title><content type='html'>&lt;p&gt;In addition to the Project Euler problems, I've been watching lectures for &lt;a href="http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/"&gt;Structure and Interpretation of Computer Programs&lt;/a&gt; by Hal Abelson and Gerald Jay Sussman.  These videos were recorded in 1986 based on their textbook of the same name.&lt;/p&gt;

&lt;p&gt;I've watched the first six lectures (1a through 3b) so far.  Having learned, done, and taught "programming languages" for close to two decades now, there's not a lot new I'm learning, but it's cool seeing their observations presented clearly and refreshing seeing guys who really get it.&lt;/p&gt;

&lt;p&gt;There were at least two things I noticed recently which I'll be blogging about in the next few days, but I figured I should give you all a heads up to get caught up with me!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5584124143442048700?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5584124143442048700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5584124143442048700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5584124143442048700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5584124143442048700'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/structure-and-interpretation-of.html' title='Structure and Interpretation of Computer Programs'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8974544901599370002</id><published>2008-07-10T16:38:00.002-04:00</published><updated>2008-07-10T16:41:31.271-04:00</updated><title type='text'>New Layout</title><content type='html'>&lt;p&gt;I've been tweaking my blog the last few days, and the last step (I hope) is changing the layout.  It's a fluid layout, so you can get my posts as wide as you like.  I'll try to keep the code narrow so that it doesn't &lt;em&gt;force&lt;/em&gt; you to go wide, but my previous layout was just way too narrow.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8974544901599370002?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8974544901599370002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8974544901599370002' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8974544901599370002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8974544901599370002'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/new-layout.html' title='New Layout'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-8933765199914406362</id><published>2008-07-09T16:23:00.002-04:00</published><updated>2008-07-10T16:19:15.173-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='prolog'/><title type='text'>PE Problem #2 in All Languages (Part II)</title><content type='html'>&lt;p&gt;In my &lt;a href="http://jdfrens.blogspot.com/2008/07/pe-problem-2-in-all-languages-part-i.html"&gt;last post&lt;/a&gt;, I described the top-level function for adding up even Fibonacci numbers less than or equal to 4 million.  The real kernel of the problem, though, is to compute &lt;a href="http://en.wikipedia.org/wiki/Fibonacci_number"&gt;Fibonacci numbers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Naively, Fibonacci numbers are computed with an exponential algorithm.  I had thought about writing this version because I suspect that even up to 4 million it wouldn't take &lt;em&gt;that&lt;/em&gt; long (although in hindsight I'm less sure).  Regardless, the challenge of writing a list-generating version sounded more interesting.  (I've written the recursive, exponential algorithm too many times to count, so by definition it's not interesting.)&lt;/p&gt;

&lt;h4&gt;Haskell&lt;/h4&gt;

&lt;p&gt;How awesome is Haskell?&lt;/p&gt;

&lt;p&gt;Don't worry.  It's a rhetorical question.  I already know that it "blinds you from over-exposure to pure awesomeness" (to paraphrase Po of &lt;a href="http://www.imdb.com/title/tt0441773/"&gt;&lt;i&gt;Kung Fu Panda&lt;/i&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;pre&gt;
fibList = 1 : 2 : zipWith (+) fibList (tail fibList)
&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;:&lt;/code&gt; operator builds up a list; &lt;code&gt;zipWith&lt;/code&gt; applies &lt;code&gt;+&lt;/code&gt; to the two lists passed to it.  Of course, if you look closely, those two lists are the same list being defined!  This works because of Haskell's &lt;a href="http://en.wikipedia.org/wiki/Lazy_evaluation"&gt;lazy evaluation&lt;/a&gt;.  Not even the &lt;code&gt;:&lt;/code&gt; operations execute until some other computation actually needs them.  So by the time the &lt;code&gt;zipWith&lt;/code&gt; is triggered, the first two elements of &lt;code&gt;fibList&lt;/code&gt; exist.&lt;/p&gt;

&lt;p&gt;To understand the &lt;code&gt;zipWith&lt;/code&gt;, let's pretend that &lt;code&gt;fibList&lt;/code&gt; is built up this far: &lt;code&gt;[1, 2, 3, 5, 8, 13]&lt;/code&gt; (plus a commitment to build more which we'll ignore for now).  So the &lt;code&gt;zipWith&lt;/code&gt; expression turns into (by substitution):&lt;/p&gt;

&lt;pre&gt;
zipWith (+) [1, 2, 3, 5, 8, 13] [2, 3, 5, 8, 13]
&lt;/pre&gt;

&lt;p&gt;This applies &lt;code&gt;+&lt;/code&gt; to each pair of elements from the two lists which results in: &lt;code&gt;[3, 5, 8, 13, 21]&lt;/code&gt;.  That's how the rest of the Fibonacci numbers are computed&amp;mdash;including the elements in that expression!&lt;/p&gt;

&lt;p&gt;This does beg the question: what triggers the computation of &lt;code&gt;fibList&lt;/code&gt;?  Answer: whatever the top-level output routine wants.  The main routine (or the tests) request a particular &lt;code&gt;fibSum&lt;/code&gt;; the &lt;code&gt;fibSum&lt;/code&gt; computation requests Fibonacci numbers from &lt;code&gt;fibList&lt;/code&gt; using this function:&lt;/p&gt;

&lt;pre&gt;
takeFibs n = takeWhile (&amp;lt;=n) fibList
&lt;/pre&gt;

&lt;p&gt;This function will only unravel &lt;code&gt;fibList&lt;/code&gt; until the limit is reached.&lt;/p&gt;

&lt;h4&gt;Erlang&lt;/h4&gt;

&lt;p&gt;For the other languages, I combined the "take" and the "Fibonacci numbers" computations.  Take a look at this:&lt;/p&gt;

&lt;pre&gt;
takeFibs(N) -&gt;
 if
   N == 0 -&gt; [];
   true   -&gt; takeFibs(N, 2, 1, [])
    end.

takeFibs(N, First, Second, Fibs) -&gt;
 if
  First &gt; N -&gt; [Second | Fibs];
  true      -&gt; takeFibs(N,
                               First + Second, First,
                               [Second | Fibs])
 end.
&lt;/pre&gt;

&lt;p&gt;There are two versions of &lt;code&gt;takeFibs&lt;/code&gt; (completely different functions because they have different numbers of parameters).  The first version is to kick off the computation and deals with the low-limit base cases.  The second version does the recursion.  It uses an accumulator-passing approach to accumulate a list of Fibonacci numbers.  The last two Fibonacci numbers computed are passed in &lt;code&gt;First&lt;/code&gt; and &lt;code&gt;Second&lt;/code&gt; to make it easier to recognize the base case and to compute the next number in the sequence.&lt;/p&gt;

&lt;p&gt;There's something about this approach that doesn't quite satisfy me.&lt;/p&gt;

&lt;h4&gt;Prolog&lt;/h4&gt;

&lt;p&gt;How does this strike you?&lt;/p&gt;

&lt;pre&gt;
takeFibs(N, L) :-
 N =:= 0 -&gt; L = [];
 N &gt; 0   -&gt; takeFibs(N, 2, 1, [], L).

takeFibs(N, First, Second, Incoming, Outgoing) :-
 First &gt; N  -&gt; Outgoing = [Second | Incoming];
 First =&amp;lt; N -&gt; Next is First+Second,
   takeFibs(N, Next, First, [Second | Incoming], Outgoing).
&lt;/pre&gt;

&lt;p&gt;It's the same approach as with Erlang.  Taking a play from the Erlang playbook, I like how the multiple cases work out this time.  Since I'm using &lt;code&gt;-&amp;gt;&lt;/code&gt;, unproductive paths through the logic are cut off so no checkpoints are left behind.&lt;/p&gt;

&lt;h4&gt;Ruby&lt;/h4&gt;

&lt;pre&gt;
class Integer
  def fibs_upto
    if zero?
      []
    else
      fibs_upto_helper(2, 1, [])
    end
  end

  private
  def fibs_upto_helper(first, second, fibs)
    if first &gt; self
      [second] + fibs
    else
      fibs_upto_helper(first + second, first, [second] + fibs)
    end
  end
end
&lt;/pre&gt;

&lt;p&gt;Same approach as the others.  It seems less slick in Ruby.&lt;/p&gt;

&lt;h4&gt;Python&lt;/h4&gt;

&lt;pre&gt;
def fibs_upto(n):
    if n == 0:
        return []
    else:
        return fibs_upto_helper(n, 2, 1, [])

def fibs_upto_helper(n, first, second, fibs):
    if first &gt; n:
        return [second] + fibs
    else:
        return fibs_upto_helper(n, first + second, first, [second] + fibs)
&lt;/pre&gt;

&lt;p&gt;Same song, same verse.  About as icky as the Ruby solution.&lt;/p&gt;

&lt;h4&gt;Options&lt;/h4&gt;

&lt;p&gt;As I've read up more about Fibonacci numbers, I suspect that a &lt;a href="http://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form"&gt;matrix approach&lt;/a&gt; might be a little more satisfying.  The non-Haskell solutions could be improved if I used infinite-list solutions in those languages, and that would actually be really interesting to work out.&lt;/p&gt;

&lt;p&gt;At this point, though, I'm willing to let this problem go since I do have it solved, and my solutions aren't bad.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-8933765199914406362?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/8933765199914406362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=8933765199914406362' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8933765199914406362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/8933765199914406362'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/pe-problem-2-in-all-languages-part-ii.html' title='PE Problem #2 in All Languages (Part II)'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-1514161238976551482</id><published>2008-07-08T17:15:00.004-04:00</published><updated>2008-07-09T13:12:44.063-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='prolog'/><title type='text'>PE Problem #2 in All Languages (Part I)</title><content type='html'>&lt;p&gt;I got busy last week with the holiday, some school obligations, and acting as a chauffeur for my grandma.  I wasn't working on Problem #2 the whole time since my last entry, honestly!&lt;/p&gt;

&lt;p&gt;Problem #2 of &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; is to add up the even &lt;a href="http://en.wikipedia.org/wiki/Fibonacci_number"&gt;Fibonacci numbers&lt;/a&gt; up to 4 million.  It actually wasn't that hard to put together my solutions (except for the Prolog one).&lt;/p&gt;

&lt;p&gt;I'm going to present my solutions in just two posts.  In this post, I'll present the top-level functions in &lt;em&gt;all&lt;/em&gt; of my languages.  In the next post, I'll present the Fibonacci-number generators.&lt;/p&gt;

&lt;h4&gt;Overview&lt;/h4&gt;

&lt;p&gt;My take on this problem was to generate Fibonacci numbers in a list (to keep the computation time linear) and then filter out just the even numbers from that list and sum them up.&lt;/p&gt;

&lt;p&gt;So the top level function has to call another function to generate the Fibonacci numbers, filter out the even Fibonacci numbers, and sum those numbers up.&lt;/p&gt;

&lt;h4&gt;Haskell&lt;/h4&gt;

&lt;p&gt;I started with Haskell because generating Fibonacci numbers are really cool in Haskell&amp;mdash;but that's for the next post.  The top level function is still pretty cool:&lt;/p&gt;

&lt;pre&gt;fibSum n = sum $ filter even $ takeFibs n&lt;/pre&gt; 

&lt;p&gt;&lt;code&gt;takeFibs&lt;/code&gt; generates a list of Fibonacci numbers less than or equal to &lt;cod&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;Erlang&lt;/h4&gt;

&lt;p&gt;I took on Erlang second.&lt;/p&gt;

&lt;pre&gt;fibSum(N) -&gt; lists:sum(
  lists:filter(fun(E) -&gt; (E rem 2) =:= 0 end, takeFibs(N))
  ).&lt;/pre&gt;

&lt;p&gt;The "even" function reads little odd to me, but otherwise I like this.&lt;/p&gt;

&lt;h4&gt;Prolog&lt;/h4&gt;

&lt;p&gt;Prolog was a bit annoying, but not this bit:&lt;/p&gt;

&lt;pre&gt;fibSum(N, Sum) :-
 takeFibs(N, Fibs),
 include(even, Fibs, EvenFibs),
 sumlist(EvenFibs, Sum).
even(N) :- N mod 2 =:= 0.
&lt;/pre&gt;

&lt;p&gt;Most of this was cribbed from one of my Prolog solutions for Problem #1.&lt;/p&gt;

&lt;h4&gt;Python&lt;/h4&gt;

&lt;p&gt;I hate code that relies on indentation.  Yuck.  Maybe I'll get use to it.  The code itself is okay.&lt;/p&gt;

&lt;pre&gt;def fib_sum(n):
    return sum(filter(even, fibs_upto(n)))
def even(n):
    return n % 2 == 0
&lt;/pre&gt;

&lt;p&gt;I switched to "&lt;code&gt;fibs_upto&lt;/code&gt;" since it made a bit more sense to me than "&lt;code&gt;takeFibs&lt;/code&gt;".&lt;/p&gt;

&lt;h4&gt;Ruby&lt;/h4&gt;

&lt;p&gt;And, finally, Ruby!&lt;/p&gt;

&lt;pre&gt;class Integer
  def fib_sum
    fibs_upto.
      select { |n| n.even? }.
      inject(0) { |sum, n| sum + n }
  end
end
&lt;/pre&gt;

&lt;p&gt;It's not bad, but kind of verbose.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-1514161238976551482?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/1514161238976551482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=1514161238976551482' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1514161238976551482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/1514161238976551482'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/07/pe-problem-2-in-all-languages-part-i.html' title='PE Problem #2 in All Languages (Part I)'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5351568293941211961</id><published>2008-06-26T22:56:00.005-04:00</published><updated>2008-07-09T13:11:50.306-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project euler'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>PE Problem #1 in Erlang</title><content type='html'>&lt;p&gt;And now I finally get to &lt;a href="http://www.trapexit.org/"&gt;Erlang&lt;/a&gt;.  I actually wrote up the code this past weekend, but a few other things got in the way of this blog entry.  I'm sure you were all waiting on pins and needles.&lt;/p&gt;

&lt;h4&gt;The Erlang Code&lt;/h4&gt;

&lt;pre&gt;sum35(N) -&gt; sum([X || X &lt;- seq(0,N), interesting_number(X)]).
interesting_number(N) -&gt; (N rem 3 == 0) or (N rem 5 == 0).
&lt;/pre&gt;

&lt;p&gt;What surprised me the most was how much Erlang borrowed its syntax from Prolog.  I had been alerted to this by a student who looked at the language for a programming languages course.  I would have guessed that Erlang's syntax had been based more on Haskell (and &lt;a href="http://miranda.org.uk/"&gt;Miranda&lt;/a&gt; and &lt;a href="http://clean.cs.ru.nl/"&gt;Clean&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;As for the solution, it seems pretty straightforward with yet another list comprehension.  I'm not sure if I like the &lt;code&gt;||&lt;/code&gt; for the "such that" in the list comprehension, but that's fairly minor.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sum&lt;/code&gt; and &lt;code&gt;seq&lt;/code&gt; come from the &lt;code&gt;list&lt;/code&gt; library.&lt;/p&gt;

&lt;h4&gt;Problems with Erlang&lt;/h4&gt;

&lt;p&gt;The biggest problem I had with Erlang was getting a unit-testing library.  My Erlang installation (from &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt;) came with &lt;a href="http://www.erlang.org/project/test_server/index.html"&gt;Erlang/OTP Test Server&lt;/a&gt;, but it's very, very heavyweight.  &lt;a href="http://svn.process-one.net/contribs/trunk/eunit/doc/overview-summary.html"&gt;eUnit&lt;/a&gt;, though, is very lightweight and very similar to the other xUnit libraries I've used.  Unfortunately, it wasn't installed by default, and it took some time getting that right.&lt;/p&gt;

&lt;p&gt;Otherwise, it was just the standard amount of time to figure out how to write and run the tests and command-line program.&lt;/p&gt;

&lt;h4&gt;What's Erlang good for?&lt;/h4&gt;

&lt;p&gt;Unfortunately, it's unlikely that the Project Euler problems will ever require me to use the distributed computing abilities of Erlang.  It's still good to use Erlang for these problems so that I get practice with the syntax.  (We'll see how long it takes me to change this tune!)&lt;/p&gt;

&lt;h4&gt;Next...&lt;/h4&gt;

&lt;p&gt;It's time to move on to Problem #2.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5351568293941211961?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5351568293941211961/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5351568293941211961' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5351568293941211961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5351568293941211961'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/06/pe-problem-1-in-erlang.html' title='PE Problem #1 in Erlang'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-7766717020429225927</id><published>2008-06-25T16:04:00.004-04:00</published><updated>2008-07-09T13:14:36.027-04:00</updated><title type='text'>My Wordles</title><content type='html'>&lt;p&gt;On &lt;a href="http://jbrains.ca/"&gt;J. B. Rainsberger's blog&lt;/a&gt; this morning, he presented an artistic tag-cloud made at &lt;a href="http://wordle.net/"&gt;Wordle&lt;/a&gt;.  It'll work off of your del.icio.us bookmarks or any text you enter in.  I couldn't resist!&lt;/p&gt;

&lt;p&gt;From the last couple of entries on this blog:&lt;/p&gt;

&lt;a href="http://wordle.net/gallery/wrdl/30510/Programming_During_Recess"  title="Wordle: Programming During Recess"&gt;&lt;img src="http://wordle.net/thumb/wrdl/30510/Programming_During_Recess"&gt;&lt;/a&gt;

&lt;p&gt;I like how the language names are so large as well as &lt;code&gt;interestingNumber&lt;/code&gt;.  I'm less happy seeing "think" so large because I think "I think" is used too much by me.  (What an awkward sentence just for a bad joke!)&lt;/p&gt;

&lt;p&gt;I also did up my &lt;a href="http://del.icio.us/jdfrens/"&gt;del.icio.us bookmarks&lt;/a&gt;:&lt;/p&gt;

&lt;a href="http://wordle.net/gallery/wrdl/30504/Jeremy%27s_bookmarks" title="Wordle: Jeremy&amp;#39;s bookmarks"&gt;&lt;img src="http://wordle.net/thumb/wrdl/30504/Jeremy%27s_bookmarks" style="padding:4px;border:1px solid #ddd"&gt;&lt;/a&gt;

&lt;p&gt;I like how big "&lt;a href="http://del.icio.us/jdfrens/java"&gt;java&lt;/a&gt;", "&lt;a href="http://del.icio.us/jdfrens/ruby"&gt;ruby&lt;/a&gt;", and "&lt;a href="http://del.icio.us/jdfrens/rails"&gt;rails&lt;/a&gt;" are; I'm a bit surprised by how big "&lt;a href="http://del.icio.us/jdfrens/webdesign"&gt;webdesign&lt;/a&gt;" is.  I also like how "&lt;a href="http://del.icio.us/jdfrens/skepticism"&gt;skepticism&lt;/a&gt;" kind of sticks out there on the left, but I'm surprised at how small it is.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-7766717020429225927?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/7766717020429225927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=7766717020429225927' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7766717020429225927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/7766717020429225927'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/06/my-wordles.html' title='My Wordles'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29454526.post-5476630558044217722</id><published>2008-06-24T16:47:00.006-04:00</published><updated>2008-07-09T13:17:37.389-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='syntax'/><title type='text'>Efficiency of cond statements</title><content type='html'>&lt;blockquote&gt;"Premature optimization is the root of all evil." --Donald Knuth&lt;/blockquote&gt;

&lt;p&gt;This is the second point which Walz raised in a comment which I thought deserved a separate blog entry.  (You can &lt;a href="http://www.blogger.com/profile/09371152762171643320"&gt;read the original comment&lt;/a&gt; and &lt;a href="http://jdfrens.blogspot.com/2008/06/return-guards-are-great-for-me-to-poop.html"&gt;the first point I liked&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Walz's second observation is about efficiency:&lt;/p&gt;

&lt;blockquote&gt;&lt;strong&gt;cond&lt;/strong&gt; statements [in LISP are] merely a construction for neat multi-branching (as opposed to nested ifs, which get ugly fast with all the parenthesis) ... I would have gone on to assume that this constant time aspect was the fundamental reason for the restrictions on C family switch statements were it not for my experiences with more expressive case statements in Haskell.&lt;/blockquote&gt;

&lt;p&gt;He goes on to ask where Ruby's &lt;code&gt;case&lt;/code&gt; statement lives in this spectrum.&lt;/p&gt;

&lt;p&gt;I should admit up front that I have my own personal demons concerning the &lt;code&gt;switch&lt;/code&gt; statement which I need to work out myself (partially through this blog).  Walz is pretty much on target here.&lt;/p&gt;

&lt;h4&gt;Performance of C &lt;code&gt;switch&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;The restrictions on C's &lt;code&gt;switch&lt;/code&gt; statement are definitely for performance reasons.  Several years ago I played around with &lt;code&gt;switch&lt;/code&gt; and &lt;code&gt;if&lt;/code&gt; statements to see how significant the difference was; I &lt;a href="http://www.calvin.edu/~jdfrens/Research/ProgLang/Switch/"&gt;wrote up my results&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I plan to revisit those results sometime on this blog and rant further about the &lt;code&gt;switch&lt;/code&gt; statement.  There are ways to lift the restrictions &lt;em&gt;and&lt;/em&gt; keep performance.&lt;/p&gt;

&lt;h4&gt;The &lt;code&gt;cond&lt;/code&gt; expression&lt;/h4&gt;

&lt;p&gt;My experience with &lt;code&gt;cond&lt;/code&gt; comes from Scheme, but I think it also applies to LISP in this case: &lt;code&gt;cond&lt;/code&gt; is implemented as a macro which expands into the standard multibranch if.  It certainly has those semantics, and so it'll have the same running time.&lt;/p&gt;

&lt;p&gt;Scheme also has a &lt;code&gt;case&lt;/code&gt; expression which is more along the lines of a C &lt;code&gt;switch&lt;/code&gt; statement.  (The main difference would be no fall-through behavior.)  But even this is turned into a mutlibranch if with &lt;code&gt;member?&lt;/code&gt; tests.&lt;/p&gt;

&lt;h4&gt;Pattern Matching in Haskell&lt;/h4&gt;

&lt;p&gt;I'm curious though about Walz's comment about Haskell.  Are you claiming that pattern matching is expressive or efficient?  It's wonderfully expressive, but it must be, in general, as expensive as a multibranch if.&lt;/p&gt;

&lt;p&gt;That's because, in general, the patterns can be very, very nested.  Since the nested components will be stored as pointers, it'll require traipsing through memory in order to find the proper match.  It can't be codified in a simple look-up table (like a &lt;code&gt;switch&lt;/code&gt; can).&lt;/p&gt;

&lt;h4&gt;Ruby's &lt;code&gt;case&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;Ruby's &lt;code&gt;case&lt;/code&gt; is wonderfully expressive, even beyond the &lt;code&gt;cond&lt;/code&gt; expression.&lt;/p&gt;

&lt;pre&gt;case grade
  when 93..100 then "A"
  when 90..92  then "A-"
  when 87..89  then "B+
  ...
&lt;/pre&gt;

&lt;p&gt;You can even put in regular expressions in for the &lt;code&gt;when&lt;/code&gt; clauses.&lt;/p&gt;

&lt;p&gt;Of course, all this expressiveness means the efficiency is like a multibranch if.&lt;/p&gt;

&lt;h4&gt;Back to efficiency&lt;/h4&gt;

&lt;p&gt;So the Scheme &lt;code&gt;case&lt;/code&gt; and &lt;code&gt;cond&lt;/code&gt;, Haskell pattern matching, and the Ruby &lt;code&gt;case&lt;/code&gt; all run (I claim) as multibranch ifs.  They don't &lt;em&gt;have&lt;/em&gt; to.  A clever compiler could recognize when these language features were being used like a &lt;code&gt;switch&lt;/code&gt; and generate a look-up table.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;real&lt;/em&gt; power is in their expressiveness.  Somehow the &lt;code&gt;switch&lt;/code&gt; statement keeps us all looking at these constructs in terms of efficiency, and that's a huge double mistake.&lt;/p&gt;

&lt;p&gt;It's a mistake because it stinks of "premature optimization" (hence my opening Knuth quote).  If a &lt;code&gt;cond&lt;/code&gt; is slow but could be made faster but executed only once when the program is started, you gain virtually nothing by optimizing it.&lt;/p&gt;

&lt;p&gt;It's also a mistake because in the general, expensive situations, the C code won't be any faster (algorithmically).  You just won't be able to use a &lt;code&gt;switch&lt;/code&gt; statement.&lt;/p&gt;

&lt;p&gt;In terms of expressiveness, they all win, certainly over the return guards&amp;mdash;which is what started all this in the first place.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29454526-5476630558044217722?l=jdfrens.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jdfrens.blogspot.com/feeds/5476630558044217722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29454526&amp;postID=5476630558044217722' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5476630558044217722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29454526/posts/default/5476630558044217722'/><link rel='alternate' type='text/html' href='http://jdfrens.blogspot.com/2008/06/efficiency-of-cond-statements.html' title='Efficiency of cond statements'/><author><name>Jeremy D. Frens</name><uri>http://www.blogger.com/profile/13179698525098485533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp3.blogger.com/_7fOA1sUkarU/SFvGdEzS1-I/AAAAAAAAAAM/51V3Y4gGrwg/S220/me.jpg'/></author><thr:total>2</thr:total></entry></feed>
