<?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-2280966215016131075</id><updated>2011-12-22T07:37:40.876-08:00</updated><category term='ruby'/><category term='fluent interfaces'/><category term='haml'/><category term='mikefinney'/><category term='nicknames'/><category term='Old School'/><category term='Noam Chomsky'/><category term='web'/><category term='community'/><category term='80s'/><category term='Nastalgia'/><category term='syntax'/><category term='office space'/><category term='java tricks'/><category term='trends'/><category term='boiler plate'/><category term='C++'/><category term='grails'/><category term='css'/><category term='ratpack'/><category term='spring'/><category term='rails'/><category term='haskell'/><category term='monitor'/><category term='layout'/><category term='vim'/><category term='productivity'/><category term='Hip-Hop'/><category term='file'/><category term='workplace'/><category term='closures'/><category term='human nature'/><category term='scheme'/><category term='scala'/><category term='emacs'/><category term='90s'/><category term='linguistics'/><category term='vi'/><category term='java'/><category term='sass'/><category term='denial'/><category term='dragons'/><category term='programming'/><category term='arc'/><category term='macros'/><category term='director'/><category term='Skepticism'/><category term='metaprogramming'/><category term='ray&apos;s stupid jokes'/><category term='lisp'/><category term='prime numbers'/><category term='lambda'/><category term='nerdcore'/><category term='gsp'/><category term='javascript dom junit java groovy testing'/><category term='PHP'/><category term='pattern matching'/><category term='paul graham'/><category term='editor'/><category term='text'/><category term='COBOL'/><category term='New York Times'/><category term='groovy'/><category term='bgga'/><category term='html'/><category term='templating'/><category term='search'/><category term='sinatra'/><category term='spj'/><category term='blogging'/><category term='talks'/><category term='recursion'/><title type='text'>(cadr life)</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-4682896699063123768</id><published>2011-05-22T13:07:00.000-07:00</published><updated>2011-05-22T13:10:55.969-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='New York Times'/><category scheme='http://www.blogger.com/atom/ns#' term='Hip-Hop'/><category scheme='http://www.blogger.com/atom/ns#' term='Nastalgia'/><category scheme='http://www.blogger.com/atom/ns#' term='Old School'/><category scheme='http://www.blogger.com/atom/ns#' term='80s'/><category scheme='http://www.blogger.com/atom/ns#' term='90s'/><title type='text'>Old School Hip-Hop Revivalists</title><content type='html'>The New York Times has a pretty neat article called "&lt;a href="http://www.nytimes.com/2011/05/15/arts/music/white-rappers-like-the-beastie-boys-pay-homage.html"&gt;White Rappers Paying Homage to the Past&lt;/a&gt;". It's definitely worth a read for Rap fans, but here's the main point: The current trend for white rappers seeking respect is a fight to revive Hip-Hop's past. You can't go wrong traveling beaten paths. Insightful but I felt part of the story was missing, so I'm throwing in my take as an 11-year Hip-Hop DJ.&lt;br /&gt;&lt;br /&gt;First, kudos. Someone at the Times must be a pretty big hip-hop head to recognize the 5 second homage to "&lt;a href="http://www.youtube.com/watch?v=xzcdmGINcqI"&gt;Smoothe da Hustler ft. Trigger tha Gambler - Broken Language&lt;/a&gt;" in the &lt;a href="http://www.youtube.com/watch?v=dhz7YcpN5rs"&gt;Action Bronson track&lt;/a&gt;. I specialize in hip-hop circa 1995 and I'd never heard of it (though the &lt;a href="http://www.youtube.com/watch?v=dGp5VZJCtHo"&gt;instrumental&lt;/a&gt; definitely makes the rounds). Unsurprising that it's obscure though, it's a 4 minute song with no chorus, just one giant verse with the same formula throughout -- listing a bunch of things that they are. Gotta admire &lt;a href="http://www.beastiemania.com/whois/kool_moe_dee/"&gt;sticking to themes&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The thesis of the article is an interesting one: many white rappers these days see themselves as preservationalists and throwback artists. Their next example was &lt;a href="http://www.youtube.com/watch?v=WdgLMslbDuY"&gt;Beastie Boys&lt;/a&gt;, which is a bit off because that's not a sign of the times. The Beastie Boys have rapped like it's '86&lt;br /&gt;since it was &lt;a href="http://www.amazon.com/Licensed-Ill-Beastie-Boys/dp/B0000024JN"&gt;'86&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Really what I think you've got here is that Hip-Hop has always been a bitterly nostalgic genre. Case in point, that very 1995 track paid homage to &lt;a href="http://www.youtube.com/watch?v=U5LoPv-BzV8"&gt;Big Daddy Kane&lt;/a&gt;, who hasn't really been relevant since &lt;a href="http://www.youtube.com/watch?v=M4Bx7R0LKx0"&gt;88&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's not necessarily a white thing, more of an underground hip-hop thing. There are plenty of examples of black rappers, underground and mainstream alike referencing tracks like&lt;br /&gt;Slick Rick's &lt;a href="http://www.youtube.com/watch?v=rt-ZE3OtKH0"&gt;La Di Da Di&lt;/a&gt; from 1985 ("La Di Da Di, we like to party..."). Amazingly, in that song Slick Rick was ALREADY complaining&lt;br /&gt;about rappers biting his rhymes, and they're still doing it 25 years later.&lt;br /&gt;&lt;br /&gt;If there has been a resurgence of the old school revivalist theme (such as Wu-Tang's recent "&lt;a href="http://www.youtube.com/watch?v=xZin6kHSmvE"&gt;Take It Back&lt;/a&gt;", Black Eyed Peas &lt;a href="http://www.youtube.com/watch?v=ZymH_uqH-No"&gt;"Bringin It Back&lt;/a&gt;" several albums ago when they were good, and virtually the entire &lt;a href="http://www.youtube.com/watch?v=XsZKrctSDaw"&gt;Jurassic 5&lt;/a&gt; catalog), I would ascribe it to the appeal of Hip-Hop as an&lt;br /&gt;underdog genre. It's reached mainstream popularity dominating the charts, so we look back fondly to the days where it was relatively esoteric. As with grunge and many others, the hardcore fanbase feels let down now that our pride and joy has been warped toward popularity.&lt;br /&gt;&lt;br /&gt;Identifying a trend with "White Rappers" is bound to get more readers, though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-4682896699063123768?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/4682896699063123768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=4682896699063123768' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/4682896699063123768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/4682896699063123768'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2011/05/old-school-hip-hop-revivalists.html' title='Old School Hip-Hop Revivalists'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-2799687604630549171</id><published>2010-12-05T20:15:00.000-08:00</published><updated>2010-12-05T20:16:02.813-08:00</updated><title type='text'>Grails Domain Objects Across Schemas</title><content type='html'>The Grails &lt;a href="http://grails.org/doc/latest/"&gt;documentation&lt;/a&gt; is very clear on how to specify specific table and column names for your domain classes (in Section 5.5.2 Custom ORM Mapping). But what if you need to specify the schema as well? Fortunately it is just as easy, if less well-documented.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/729827.js?file=book.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Of course, when all of your domain tables are in the same schema, you should simply specify a default schema in &lt;i&gt;DataSource.groovy&lt;/i&gt;. The property is &lt;i&gt;hibernate.default_schema&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-2799687604630549171?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/2799687604630549171/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=2799687604630549171' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/2799687604630549171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/2799687604630549171'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2010/12/grails-domain-objects-across-schemas.html' title='Grails Domain Objects Across Schemas'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-6066500413940596181</id><published>2010-08-05T20:27:00.000-07:00</published><updated>2010-08-05T20:35:04.604-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript dom junit java groovy testing'/><title type='text'>Testing rich webapps from JUnit with Rhino and Envjs</title><content type='html'>&lt;a href="http://github.com/thatcher/env-js"&gt;Envjs&lt;/a&gt; is an implementation of the DOM in Javascript. Together with &lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt;, it can function as a headless web browser in Java. Picture &lt;a href="http://htmlunit.sourceforge.net/"&gt;HtmlUnit&lt;/a&gt;, but with flawless Javascript support. For instance, the latest version of JQuery works flawlessly in Envjs on Rhino but won't even load in HtmlUnit.&lt;br /&gt;&lt;br /&gt;Here's a simple way to tie them together in JUnit. Wonderful testing frameworks to follow (looking at you, &lt;a href="http://finneycanhelp.blogspot.com/"&gt;Mike&lt;/a&gt; ;)&lt;br /&gt;&lt;br /&gt;Not too many Groovy-isms here, can easily be converted to plain Java.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/510770.js?file=EnvJsRhinoTest.groovy"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-6066500413940596181?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/6066500413940596181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=6066500413940596181' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/6066500413940596181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/6066500413940596181'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2010/08/testing-rich-webapps-from-junit-with.html' title='Testing rich webapps from JUnit with Rhino and Envjs'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-5099990583565141903</id><published>2010-07-23T12:00:00.000-07:00</published><updated>2010-07-24T15:26:56.772-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='monitor'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='file'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='sinatra'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='ratpack'/><category scheme='http://www.blogger.com/atom/ns#' term='director'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Watch Directory For Changes in Groovy</title><content type='html'>One must-have feature in any &lt;b&gt;modern&lt;/b&gt; web stack is the ability to automatically restart/refresh the development server when you edit the source code. It is critical for developer workflow that the feedback loop be as tight as possible. Here source code refers to actual class definitions, templates (JSPs, GSPs, &lt;a href="http://haml-lang.com/"&gt;haml&lt;/a&gt; files, etc...), static content (javascript, css, images), AND configuration (I'm looking at you, struts.xml).&lt;br /&gt;&lt;br /&gt;All web frameworks which do not support automatic updating of all content during development shall hereafter be referred to as "Legacy Web Frameworks". Is your shop using them?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://justinvoss.com/"&gt;Justin Voss&lt;/a&gt; and I have been hard at work on a web micro-framework called &lt;a href="http://github.com/bleedingwolf/Ratpack"&gt;Ratpack&lt;/a&gt; (inspired by Ruby's &lt;a href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt;). Lest it become a Legacy Web Framework right out of the gate, we've implemented basic auto-reloading right away. Feel free to grab this for other uses, as it works independently.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;groovy runapp.groovy app/myapp.groovy app&lt;/blockquote&gt;&lt;br /&gt;The script &lt;i&gt;app/myapp.groovy&lt;/i&gt; will be killed and re-run when any content in the &lt;i&gt;app&lt;/i&gt; directory changes.&lt;br /&gt;&lt;br /&gt;Since &lt;a href="http://github.com/bleedingwolf/Ratpack"&gt;Ratpack&lt;/a&gt; uses &lt;a href="http://jetty.codehaus.org/jetty/"&gt;Jetty&lt;/a&gt;, there are probably better solutions. Feedback is welcome.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/487813.js?file=runapp.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://java.sun.com/developer/technicalArticles/javase/nio/"&gt;NIO.2 Filesystem&lt;/a&gt; in JDK7 will make this sort of thing much easier.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-5099990583565141903?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/5099990583565141903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=5099990583565141903' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/5099990583565141903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/5099990583565141903'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2010/07/watch-directory-for-changes-in-groovy.html' title='Watch Directory For Changes in Groovy'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-6220262523948484401</id><published>2010-05-09T10:31:00.000-07:00</published><updated>2010-05-15T19:58:20.878-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='templating'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='haml'/><category scheme='http://www.blogger.com/atom/ns#' term='gsp'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Haml For Grails</title><content type='html'>Writing a Grails app? Find out why so many &lt;a href="http://ruby-toolbox.com/categories/template_languages.html"&gt;Rubyists&lt;/a&gt; swear by &lt;a href="http://haml-lang.com/"&gt;Haml&lt;/a&gt; for writing views.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/395294.js?file=haml-example1.jsp"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/td&gt; &lt;td&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/395296.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/table&gt;Interested parties have created &lt;a href="http://github.com/raymyers/JHaml"&gt;JHaml&lt;/a&gt;, a Java implementation of Haml, and a corresponding &lt;a href="http://github.com/raymyers/haml4grails"&gt;Grails plugin&lt;/a&gt;. (Patches welcome!)&lt;br /&gt;&lt;br /&gt;To try it out, just grab the plugin:&lt;br /&gt;&lt;blockquote&gt;grails install-plugin haml&lt;/blockquote&gt;Then add this bean definition to your &lt;i&gt;grails-app/conf/spring/resources.groovy&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/394801.js"&gt;&lt;/script&gt;&lt;br /&gt;Now, you have the option of writing views (with the .haml extension) that will be automatically rendered to GSPs.&lt;br /&gt;&lt;br /&gt;Learn more in the Haml &lt;a href="http://haml-lang.com/tutorial.html"&gt;tutorial&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.grails.org/plugin/haml"&gt;Official Grails Plugin Page&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-6220262523948484401?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/6220262523948484401/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=6220262523948484401' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/6220262523948484401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/6220262523948484401'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2010/05/haml-for-grails.html' title='Haml For Grails'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-1945111795502166947</id><published>2010-04-18T09:13:00.000-07:00</published><updated>2010-04-18T09:24:40.675-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='layout'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='haml'/><category scheme='http://www.blogger.com/atom/ns#' term='sass'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>"Holy Grail" Three-Column Layout in Haml and Sass</title><content type='html'>Thanks to Matthew Levine for his article&lt;a href="http://www.alistapart.com/articles/holygrail"&gt; In Search of the Holy Grail&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/370320.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Feel free to post your own variants!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-1945111795502166947?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/1945111795502166947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=1945111795502166947' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/1945111795502166947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/1945111795502166947'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2010/04/holy-grail-three-column-layout-in-haml.html' title='&quot;Holy Grail&quot; Three-Column Layout in Haml and Sass'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-255075641589612373</id><published>2009-01-12T16:30:00.000-08:00</published><updated>2009-05-04T11:15:49.206-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='boiler plate'/><title type='text'>Beyond web.xml</title><content type='html'>Another day paying the bills in Eclipse...&lt;br /&gt;&lt;pre class="prettyprint"&gt;public class HelloWorldServlet extends HttpServlet {&lt;br /&gt;    private static final long serialVersionUID = 1L;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    protected void doGet(HttpServletRequest req, HttpServletResponse resp) &lt;br /&gt;            throws ServletException, IOException {&lt;br /&gt;        resp.getWriter().println("Hello World!");&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;So you've just written yourself a spiffy little servlet and you want to test it out. That's when it hits you... there is a long and arduous road ahead. You've got to remember how to deploy a &lt;a href="http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/WebComponents3.html"&gt;War&lt;/a&gt; (how does that Ant script go again?). You need to configure &lt;a href="http://tomcat.apache.org/"&gt;Tomcat&lt;/a&gt; (Or wait 20 minutes for Weblogic to start). Then you need to write that dreaded &lt;a href="http://www.adp-gmbh.ch/java/web_application/web_xml.html"&gt;web.xml&lt;/a&gt; file. &lt;span style="font-style:italic;"&gt;This is a barren wasteland, riddled with fire and ash and dust. The very air you breathe is a poisonous fume. Not with ten thousand men could you do this. Tis folly!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Dag-nabbit! You aren't writing a big fancy industrial strength web app. All you want to do is run your little servlet in a local web browser and get on with your life! Jiminy Cricket, it's times like this that can turn a developer to &lt;a href="http://www.youtube.com/watch?v=PQbuyKUaKFo"&gt;Rails&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So what are you going to do? Bite the bullet and muddle through it all for the umpteenth time? Give up and write a command line app? Recall that the three chief &lt;a href="http://en.wikiquote.org/wiki/Larry_Wall"&gt;virtues&lt;/a&gt; of a programmer are: Laziness, Impatience, and Hubris. Where there is a will, there is a way.&lt;br /&gt;&lt;br /&gt;Grab yourself a &lt;a href="http://www.mortbay.org/jetty/"&gt;Jetty&lt;/a&gt; jar and throw one of these in your app: &lt;pre class="prettyprint"&gt;import org.mortbay.jetty.Server;&lt;br /&gt;import org.mortbay.jetty.servlet.Context;&lt;br /&gt;import org.mortbay.jetty.servlet.ServletHolder;&lt;br /&gt;&lt;br /&gt;public class EmbeddedServletRunner {&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        Server server = new Server(8080);&lt;br /&gt;        Context root = new Context(server,"/",Context.SESSIONS);&lt;br /&gt;        root.addServlet(new ServletHolder(new HelloWorldServlet()), "/hello");&lt;br /&gt;        server.start();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Run it. Point your browser to &lt;span style="font-weight:bold;"&gt;http://localhost:8080/hello&lt;/span&gt; and you're good to go.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-255075641589612373?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/255075641589612373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=255075641589612373' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/255075641589612373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/255075641589612373'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2009/01/beyond-webxml.html' title='Beyond web.xml'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-8406694082076600292</id><published>2008-10-26T00:29:00.000-07:00</published><updated>2008-10-27T10:10:33.533-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='human nature'/><category scheme='http://www.blogger.com/atom/ns#' term='vi'/><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><category scheme='http://www.blogger.com/atom/ns#' term='text'/><category scheme='http://www.blogger.com/atom/ns#' term='editor'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Ladies and Gentlemen, The Editor War</title><content type='html'>Scene opens. The Lakota coffee shop in Columbia, MO.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: ... and the other has been really interesting. It's Anthropology, with Jim Metcher.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: (lights up) Yes! I actually got to take one of Metcher's classes during my brief stint in the evening program.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: Are a Mizzou student?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: Close. I graduated from MST in '06. I'm workin' now.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: What do you do?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: I help machines think. I'm a programmer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: Spiffy! So what's new in the fast-paced world of "programming"?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: Well, lot's of things I guess. Let's see... new languages coming out as usual. PHP making some controversial design decisions regarding namespace. 50th anniversary of Lisp was just celebrated at OOPSLA; I bet there were some great talks at that. Oh yeah, and I just read about a new &lt;a href="http://upsilon.cc/~zack/blog/posts/2008/10/from_Vim_to_Emacs_-_part_1/"&gt;development&lt;/a&gt; in The Editor War.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: ... The editor &lt;span style="font-style:italic;"&gt;what&lt;/span&gt;?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: War. The Editor War... it's this infamous feud. (waves hand dismissively)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: Feud? (interest grows at the scent of scandal) Over what?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: Which text editor to use.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: (Smirk) No, really. What is it about? I'm actually interested this time, you don't have to make things up to amuse me.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: No... (Slowly raises hand to forehead), that's actually what it's about.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: (Confused) That doesn't sound like a very political decision. Is there some, like, protocol or something that has to... (pauses) I thought &lt;span style="font-style:italic;"&gt;text&lt;/span&gt; was all sort of... &lt;span style="font-style:italic;"&gt;compatible&lt;/span&gt;. (glances downward) I guess I don't much about this stuff.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: Actually, you've got a decent grasp of it. While there have been a few new standards in recent years to accommodate different languages, text is overall very compatible from one editor to the next.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: In that case, I don't get it. What other technical hurdle would force all programmers to use the same editor?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: Ahh! I see the source of your confusion. That's not the issue. We're not debating the adoption of an official industry-wide standard editor. Nothing along those lines. It's a matter of personal preference.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: (Disappointed) So it's just different people choosing a different tool? Aren't you exaggerating a bit by calling it a feud? &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: I see where you might think that, but believe it or not, I've been to parties where shouting matches broke out spontaneously at the mention of either of these editors.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: Really?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: Really.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: Wow. So this has been going on for what, weeks now?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: A bit longer than that.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jane&lt;/span&gt;: Months?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ray&lt;/span&gt;: It has been going on for over 25 years.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-8406694082076600292?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/8406694082076600292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=8406694082076600292' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/8406694082076600292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/8406694082076600292'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/10/ladies-and-gentlemen-editor-war.html' title='Ladies and Gentlemen, The Editor War'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-99612397519374492</id><published>2008-07-16T22:59:00.000-07:00</published><updated>2008-12-11T09:39:29.373-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='lambda'/><category scheme='http://www.blogger.com/atom/ns#' term='denial'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>Clone Wizards of Time and Space</title><content type='html'>The talk, &lt;a href="http://mwrc2008.confreaks.com/03bowkett.html"&gt;Code Generation: The Safety Scissors Of Metaprogramming&lt;/a&gt; by Giles Bowkett.&lt;br /&gt;&lt;br /&gt;The quote, "This is how Lisp guys think of Lisp and the Lisp community: intergalactic voluntarily bald clone wizards of time and space who the womens are be lusting fors."&lt;br /&gt;&lt;br /&gt;He literally said that. I'm not paraphrasing. One more time in case you missed it.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Xk3k6lsmUxU/SH7hmL3DhPI/AAAAAAAAABY/LpZG4jUbj2U/s1600-h/lispers-of-time-and-space.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_Xk3k6lsmUxU/SH7hmL3DhPI/AAAAAAAAABY/LpZG4jUbj2U/s320/lispers-of-time-and-space.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5223860663931340018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style:italic;"&gt;Intergalactic Voluntarily Bald Clone Wizards of Time and Space Who The Womens Are Be Lusting Fors.&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I for one am quite offended! I resent the continuing perception that &lt;a href="http://www.serve.com/cmtan/buddhism/Lighter/aikoans.html"&gt;Lispers&lt;/a&gt; are &lt;a href="http://smuglispweeny.blogspot.com/"&gt;smug&lt;/a&gt; and arrogant. Nothing could be further from the truth! We do not see ourselves as some sort of &lt;a href="http://www.catb.org/jargon/html/K/Knights-of-the-Lambda-Calculus.html"&gt;secret society&lt;/a&gt; with magic &lt;a href="http://xkcd.com/297/"&gt;powers&lt;/a&gt; beyond the comprehension of you mere &lt;a href="http://java.sun.com/"&gt;mortals&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Signed,&lt;br /&gt;Ray, Squire of the Grand Recursive Order of the Knights of the Lambda Calculus&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-99612397519374492?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/99612397519374492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=99612397519374492' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/99612397519374492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/99612397519374492'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/07/clone-wizards-of-time-and-space.html' title='Clone Wizards of Time and Space'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Xk3k6lsmUxU/SH7hmL3DhPI/AAAAAAAAABY/LpZG4jUbj2U/s72-c/lispers-of-time-and-space.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-3891582561961318738</id><published>2008-07-12T00:48:00.000-07:00</published><updated>2008-07-14T19:47:01.060-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='search'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Learn Recursion</title><content type='html'>Todays message is short and sweet.&lt;br /&gt;&lt;br /&gt;I was just reading chapter seven of &lt;span style="font-style:italic;"&gt;Beautiful Code&lt;/span&gt;, "Beautiful Testing". As the chapter begins, the reader is challenged to attempt writing a binary search. Here's mine.&lt;br /&gt;&lt;pre&gt;int search(int[] arr, int target) {&lt;br /&gt;    return arr.length == 0 ? -1 : search(arr, target, 0, arr.length-1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int search(int[] arr, int target, int min, int max) {&lt;br /&gt;    if (min &gt;= max) return target == arr[min] ? min : -1;&lt;br /&gt;    int middle =  (max + min) &gt;&gt;&gt; 1;&lt;br /&gt;    if (arr[middle] &gt; target) return search(arr, target, min, middle-1);&lt;br /&gt;    if (arr[middle] &lt; target) return search(arr, target, middle+1, max);&lt;br /&gt;    return middle;&lt;br /&gt;}&lt;/pre&gt;Yes, it's in Java. I'm not going to rewrite it in eight other languages because that's not the point, for once.&lt;br /&gt;&lt;br /&gt;Here's the point: If you call yourself a programmer and don't grok this recursion business, fix it. Now.&lt;br /&gt;&lt;br /&gt;This has been a public service announcement brought to you by the "People Who Will Not Take You Seriously If You Don't Understand Recursion" Foundation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-3891582561961318738?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/3891582561961318738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=3891582561961318738' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/3891582561961318738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/3891582561961318738'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/07/learn-recursion.html' title='Learn Recursion'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-2793100537472464229</id><published>2008-07-01T22:38:00.000-07:00</published><updated>2008-09-28T20:09:06.426-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Skepticism'/><title type='text'>The arrogance of demanding evidence</title><content type='html'>&lt;blockquote&gt;"No one has the right to destroy another person's belief by&lt;br /&gt;demanding empirical evidence." — Ann Landers&lt;/blockquote&gt; &lt;br /&gt;This is widely quoted but I haven't found a full citation of the original source. Thus, it's remotely possible that this is a misquote, out of context, etc...&lt;br /&gt;&lt;br /&gt;Still, I'm not too worried about misquoting a shared pen name. My main concern is that in 2008, it is still possible to read a quote like this without flinching. One might even &lt;span style="font-style:italic;"&gt;agree&lt;/span&gt;!&lt;br /&gt;&lt;br /&gt;The statement implies two things. The first is that the freedom of speech should be abolished. (We'll look past that one for now.) The second is that it is unreasonable, inhumane, and simply impolite to expect people to base their worldviews on ... the world. In intellectual discourse, once someone says the magic words "I believe," it is inappropriate for other parties to continue further.&lt;br /&gt;&lt;br /&gt;In fact, a more honest phrasing of the Ann Landers quote might be:&lt;br /&gt;&lt;br /&gt;"Don't speak up; you might inadvertently cause someone to change their mind."&lt;br /&gt;&lt;br /&gt;I've had my beliefs turned upside-down by empirical evidence dozens of times in my life, and I'm probably not done. I used to believe that aliens crashed in Roswell, New Mexico in 1947. I used to believe that Uri Geller was psychic. I used to believe that homeopathic preparations had medicinal properties. I used to believe that computers couldn't think — and would never think.&lt;br /&gt;&lt;br /&gt;I am a better person for being able to change my mind.&lt;br /&gt;&lt;br /&gt;"It is far better to grasp the universe as it really is than to persist in delusion, however satisfying and reassuring." — Carl Sagan&lt;br /&gt;&lt;br /&gt;"Isn't it enough to see that a garden is beautiful without having to believe that there are fairies at the bottom of it too?" — Douglas Adams&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-2793100537472464229?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/2793100537472464229/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=2793100537472464229' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/2793100537472464229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/2793100537472464229'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/07/arrogance-of-demanding-evidence.html' title='The arrogance of demanding evidence'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-3955132473672083658</id><published>2008-04-10T04:22:00.000-07:00</published><updated>2008-04-13T17:12:58.354-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='closures'/><category scheme='http://www.blogger.com/atom/ns#' term='bgga'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Subsequences With BGGA Closures</title><content type='html'>Just a quick followup on &lt;a href="http://cadrlife.blogspot.com/2008/03/returning-considered-difficult.html"&gt;Returning '(()) Considered Difficult&lt;/a&gt;. I just rewrote the "subsequences of length n" exercise yet again (surprise, surprise), this time using the Java &lt;a href="http://www.javac.info/"&gt;BGGA&lt;/a&gt; prototype by Neal Gafter et al. I really like being able to abstract away the accumulation loop.&lt;br /&gt;&lt;pre&gt;import static com.cadrlife.ListUtils.*;&lt;br /&gt;...&lt;br /&gt;private static &amp;lt;T&gt; List&amp;lt;List&amp;lt;T&gt;&gt; subn(int n, List&amp;lt;T&gt; list) {&lt;br /&gt;    if (n == 0) {&lt;br /&gt;        return Collections.&amp;lt;List&amp;lt;T&gt;&gt;singletonList(new ArrayList&amp;lt;T&gt;());&lt;br /&gt;    }&lt;br /&gt;    if (list.isEmpty()) {&lt;br /&gt;        return new ArrayList&amp;lt;List&amp;lt;T&gt;&gt;();&lt;br /&gt;    }&lt;br /&gt;    T first = list.get(0);&lt;br /&gt;    List&amp;lt;T&gt; rest = list.subList(1, list.size());&lt;br /&gt;    return addAll(collect(subn(n-1, rest), {List&amp;lt;T&gt; sub =&gt; push(first, sub)}), &lt;br /&gt;                  subn(n, rest));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;A word on syntax:&lt;/span&gt; Some people have come down on the {=&gt;} closure syntax but I wonder if they have actually used it. This was my first time using BGGA; everything compiled and worked on the first try. I can't say the same about trying to simulate closures with anonymous Transformer classes using the Apache Commons &lt;a href="http://commons.apache.org/collections/api/org/apache/commons/collections/CollectionUtils.html"&gt;CollectionUtils&lt;/a&gt; version of collect.&lt;br /&gt;&lt;br /&gt;Just in case you don't have com.cadrlife.ListUtils in your classpath, here are the obvious definitions of &lt;span style="font-style:italic;"&gt;collect&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;addAll&lt;/span&gt;, and &lt;span style="font-style:italic;"&gt;push&lt;/span&gt;.&lt;br /&gt;&lt;pre&gt;package com.cadrlife.ListUtils;&lt;br /&gt;...&lt;br /&gt;public static &amp;lt;A,B&gt; List&amp;lt;B&gt; collect(List&amp;lt;A&gt; list, {A =&gt; B} function) {&lt;br /&gt;    List&amp;lt;B&gt; result = new ArrayList&amp;lt;B&gt;();&lt;br /&gt;    for (A element : list) {&lt;br /&gt;        result.add(function.invoke(element));&lt;br /&gt;    }       &lt;br /&gt;    return result; &lt;br /&gt;}&lt;br /&gt;public static &amp;lt;T&gt; List&amp;lt;T&gt; push(T el, List&amp;lt;T&gt; list) {&lt;br /&gt;    list.add(0, el);&lt;br /&gt;    return list;&lt;br /&gt;}   &lt;br /&gt;&lt;br /&gt;public static &amp;lt;T&gt; List&amp;lt;T&gt; addAll(List&amp;lt;T&gt; a, List&amp;lt;T&gt; b) {&lt;br /&gt;    a.addAll(b);&lt;br /&gt;    return a;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;FunctionalJ:&lt;/span&gt; &lt;a href="http://buildwithoutboundaries.blogspot.com/"&gt;Steve&lt;/a&gt; points out that the last bit could be done this way, using the Java library &lt;a href="http://functionalj.sourceforge.net/"&gt;FunctionalJ&lt;/a&gt;. &lt;br /&gt;&lt;pre&gt;DynReflect reflect = new JdkDynReflect();&lt;br /&gt;Function1 pushFirstElem = reflect.staticFunction(&lt;br /&gt;        AnnotatedSequencer.class, "push").f2().bind(first(list));&lt;br /&gt;return addAll(map(pushFirstElem, subn(n - 1, tail(list))),&lt;br /&gt;        subn(n, tail(list)));&lt;/pre&gt;Be forewarned that using reflection to simulate first-order functions in this way will sacrifice compile-time verification.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-3955132473672083658?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/3955132473672083658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=3955132473672083658' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/3955132473672083658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/3955132473672083658'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/04/subsequences-with-bgga-closures.html' title='Subsequences With BGGA Closures'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-4439612223663476312</id><published>2008-03-29T21:43:00.000-07:00</published><updated>2008-07-06T11:04:37.555-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Returning '(()) Considered Difficult</title><content type='html'>Suppose you want a function to find all &lt;a href="http://en.wikipedia.org/wiki/Subsequence"&gt;subsequences&lt;/a&gt; of a list with a certain length. For instance, the subsequences of (1...5) with length 2 are as follows.&lt;br /&gt;&lt;pre&gt;(1 2) (1 3) (1 4) (1 5)&lt;br /&gt;(2 3) (2 4) (2 5)&lt;br /&gt;(3 4) (3 5)&lt;br /&gt;(4 5)&lt;/pre&gt;This is not a red-herring example cooked up just to make Java look bad. This actually came up at work! I did something along these lines. Yuck.&lt;br /&gt;&lt;pre&gt;private static &amp;lt;T&gt; List&amp;lt;List&amp;lt;T&gt;&gt; subn(int n, List&amp;lt;T&gt; li) {&lt;br /&gt;  List&amp;lt;List&amp;lt;T&gt;&gt; ret = new ArrayList&amp;lt;List&amp;lt;T&gt;&gt;();&lt;br /&gt;  if (n == 0) {&lt;br /&gt;      ret.add(new ArrayList&amp;lt;T&gt;());&lt;br /&gt;      return ret;&lt;br /&gt;  }&lt;br /&gt;  if (li.isEmpty()) {&lt;br /&gt;      return ret;&lt;br /&gt;  }&lt;br /&gt;  T x = li.get(0);&lt;br /&gt;  List&amp;lt;T&gt; xs = li.subList(1, li.size());&lt;br /&gt;  for (List&amp;lt;T&amp;gt; sub : subn(n-1, xs)) {&lt;br /&gt;      sub.add(0, x);&lt;br /&gt;      ret.add(sub);&lt;br /&gt;  }&lt;br /&gt;  ret.addAll(subn(n, xs));&lt;br /&gt;  return ret;&lt;br /&gt;}&lt;/pre&gt;However, that was not the way my thoughts originally took shape. I think in Lisp.&lt;br /&gt;&lt;pre&gt;(def subn (n li)&lt;br /&gt; (if (is 0 n) '(())&lt;br /&gt;     (no li) '()&lt;br /&gt;       (join (map [cons (car li) _] (subn (- n 1) (cdr li)))&lt;br /&gt;             (subn n (cdr li)))))&lt;/pre&gt;Then I moved it to Haskell for greater clarity.&lt;br /&gt;&lt;pre&gt;subn 0 _      = [[]]&lt;br /&gt;subn _ []     = []&lt;br /&gt;subn n (x:xs) = map (x:) (subn (n-1) xs) ++ subn n xs&lt;/pre&gt;With great pain, I converted those three lines of Haskell into the ugly splatter of Java you saw above. Later on, I started playing around with &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt; and gradually compacted the Java into something strikingly similar to its Haskell ancestor.&lt;br /&gt;&lt;pre&gt;def subn[T](n: int, li : List[T]) : List[List[T]] = (n,li) match {&lt;br /&gt;   case (0,_)     =&gt; List(Nil)&lt;br /&gt;   case (_,Nil)   =&gt; Nil&lt;br /&gt;   case (_,x::xs) =&gt; (subn(n-1, xs) map (x :: _)) ::: subn(n, xs)&lt;br /&gt;}&lt;/pre&gt;The title of today's post refers to the inordinate amount of trouble it is to simply return "The list containing the empty list" in Java. I tried such monstrosities as these:&lt;br /&gt;&lt;pre&gt;Collections.singletonList(Collections.EMPTY_LIST) // List&amp;lt;List&amp;gt;&lt;br /&gt;Arrays.asList(Collections.emptyList()) // List&amp;lt;List&amp;lt;Object&amp;gt;&amp;gt;&lt;br /&gt;Collections.singletonList(new ArrayList&amp;lt;T&amp;gt;()) // List&amp;lt;ArrayList&amp;lt;T&amp;gt;&amp;gt;&lt;br /&gt;Collections.singletonList((List&amp;lt;T&amp;gt;)new ArrayList&amp;lt;T&amp;gt;()) // List&amp;lt;List&amp;lt;T&amp;gt;&amp;gt;&lt;/pre&gt;The last option does give the correct type, but it causes a compiler warning and is not much less cumbersome than the naive approach, i.e.:&lt;br /&gt;&lt;pre&gt;List&amp;lt;List&amp;lt;T&gt;&gt; ret = new ArrayList&amp;lt;List&amp;lt;T&gt;&gt;();&lt;br /&gt;ret.add(new ArrayList&amp;lt;T&gt;());&lt;br /&gt;return ret;&lt;/pre&gt;So here's a challenge for you Java developers out there. What would you change about the admittedly sloppy Java code at the beginning of this post? I'm issuing an all points bulletin to the refactoring mavericks (&lt;a href="http://finneycanhelp.blogspot.com/"&gt;Mike&lt;/a&gt;, &lt;a href="http://www.james-carr.org/"&gt;James&lt;/a&gt;), the simple-design visionaries (&lt;a href="http://buildwithoutboundaries.blogspot.com/"&gt;Steve&lt;/a&gt;), and the speed-freak optimizers (Dan). I wouldn't even mind seeing a C# version (&lt;a href="http://codeclimber.blogspot.com/"&gt;Ethan&lt;/a&gt;), or an improvement on the Haskell (Eric).&lt;br /&gt;&lt;br /&gt;Incidentally, I know some people think &lt;a href="http://www.xkcd.com/244/"&gt;recursion&lt;/a&gt; is hard to read. I'd love to see an iterative solution as well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;P.S.&lt;/span&gt; I realize that the comment boxes don't hold code blocks very well. Feel free to &lt;a href="http://pastebin.com/f786ea21b"&gt;link&lt;/a&gt; to a solution.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Updates:&lt;/span&gt;&lt;br /&gt;Based on your input, I am now happy to give three different ways of returning '(()) in one line. I am only including ways that would work in the context I gave (i.e. the inner list must be mutable). The last is my favorite because the others cause compiler warnings.&lt;pre&gt;return Arrays.&amp;lt;List&amp;lt;T&gt;&gt;asList(new ArrayList&amp;lt;T&gt;());&lt;br /&gt;// Type safety : A generic array of ArrayList&lt;T&gt; is created for a varargs parameter&lt;br /&gt;&lt;br /&gt;return new ArrayList&amp;lt;List&amp;lt;T&gt;&gt;() {{add(new ArrayList&amp;lt;T&gt;());}};&lt;br /&gt;// The serializable class does not declare a static final serialVersionUID...&lt;br /&gt;// Ricky points out that this is an "Eclipse warning".&lt;br /&gt;&lt;br /&gt;return Collections.&amp;lt;List&amp;lt;T&gt;&gt;singletonList(new ArrayList&amp;lt;T&gt;());&lt;br /&gt;// No warnings :)&lt;/pre&gt;Eric has blessed us with a &lt;a href="http://hpaste.org/6849"&gt;version&lt;/a&gt; in &lt;a href="http://factorcode.org/"&gt;Factor&lt;/a&gt; (not to be confused with my &lt;span style="font-style:italic;"&gt;aversion&lt;/span&gt; to Factor). He also added a Haskell version using list comprehensions to achieve better laziness properties.&lt;br /&gt;&lt;br /&gt;Meanwhile, back in &lt;a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html"&gt;Javaland&lt;/a&gt;, Dan suggested using &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/SortedSet.html"&gt;SortedSet&lt;/a&gt;, particularly the &lt;span style="font-style:italic;"&gt;subSet&lt;/span&gt; method. This seems to be a dead end in this case, but is certainly a useful corner of the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collection.html"&gt;Collection&lt;/a&gt; hierarchy.&lt;br /&gt;&lt;br /&gt;After briefly attaining List Enlightenment, Thomas produced an implementation in Java with no recursion. Aside from being much longer and totally opaque, it also has worse performance charactoristics. It essentially produces &lt;span style="font-style:italic;"&gt;every&lt;/span&gt; subsequence and then filters by length, similar to the Haskell one-liner suggested in the comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-4439612223663476312?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/4439612223663476312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=4439612223663476312' title='25 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/4439612223663476312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/4439612223663476312'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/03/returning-considered-difficult.html' title='Returning &apos;(()) Considered Difficult'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>25</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-1506563064668096597</id><published>2008-03-26T19:10:00.000-07:00</published><updated>2009-07-11T14:14:00.907-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='talks'/><category scheme='http://www.blogger.com/atom/ns#' term='spj'/><title type='text'>Speaker Spotlight - Simon Peyton-Jones</title><content type='html'>&lt;a href="http://research.microsoft.com/%7Esimonpj/"&gt;Simon Peyton-Jones&lt;/a&gt; was one of the designers of the &lt;a href="http://www.haskell.org/"&gt;Haskell&lt;/a&gt; programming language. Here are links some of his &lt;a href="http://xkcd.com/153/"&gt;presentations&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;A Taste of Haskell&lt;/span&gt;&lt;br /&gt;Introduction to Haskell with XMonad as an example&lt;br /&gt;(&lt;a href="http://blip.tv/file/324976"&gt;video 1&lt;/a&gt;) (&lt;a href="http://blip.tv/file/325646"&gt;video 2&lt;/a&gt;) (&lt;a href="http://conferences.oreillynet.com/presentations/os2007/os_peytonjones.pdf"&gt;slides&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Composing Contracts - An Adventure in Financial Engineering&lt;/span&gt;&lt;br /&gt;Very interesting case study on domain specific languages&lt;br /&gt;(&lt;a href="http://ulf.wiger.net/weblog/2008/02/29/simon-peyton-jones-composing-contracts-an-adventure-in-financial-engineering/"&gt;video&lt;/a&gt;) (&lt;a href="http://ulf.wiger.net/fp_seminar/Options-Ericsson-Feb08.pdf"&gt;slides&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Nested Data Parallelism in Haskell&lt;/span&gt;&lt;br /&gt;Beating FORTRAN is the name of the game!&lt;br /&gt;(&lt;a href="http://www.londonhug.net/2007/09/25/nested-data-parallelism-video-returns/"&gt;video&lt;/a&gt;) (&lt;a href="http://www.londonhug.net/wp-content/uploads/2007/05/nested-data-parallelism.ppt"&gt;slides&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Taming Effects - The Next Big Challenge&lt;/span&gt;&lt;br /&gt;The virtues of purity in functional languages&lt;br /&gt;(&lt;a href="http://ulf.wiger.net/weblog/2008/02/29/peyton-jones-taming-effects-the-next-big-challenge/"&gt;video&lt;/a&gt;) (&lt;a href="http://ulf.wiger.net/fp_seminar/Effects_Ericsson_Feb08.pdf"&gt;slides&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Transactional Memory for Concurrency&lt;/span&gt;&lt;br /&gt;OSCON 2007 Keynote&lt;br /&gt;(&lt;a href="http://www.blip.tv/file/317758/"&gt;video&lt;/a&gt;) (&lt;a href="http://research.microsoft.com/%7Esimonpj/papers/stm/STM-OSCON.pdf"&gt;slides&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Programming in the Age of Concurrency: Software Transactional Memory&lt;/span&gt;&lt;br /&gt;Interview with Simon and &lt;a href="http://research.microsoft.com/%7Etharris/"&gt;Tim Harris&lt;/a&gt; about Transactional Memory&lt;br /&gt;(&lt;a href="http://channel9.msdn.com/Showpost.aspx?postid=231495"&gt;video&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Type-driven Testing&lt;/span&gt;&lt;br /&gt;Demonstration of the Haskell library QuickCheck&lt;br /&gt;(&lt;a href="http://www.foomongers.org.uk/videos/spj-typedriventestinginhaskell.html"&gt;video&lt;/a&gt;) (&lt;a href="http://www.foomongers.org.uk/videos/spj-typedriventestinginhaskell.pdf"&gt;slides&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Haskell and Erlang: Growing Up Together&lt;/span&gt;&lt;br /&gt;At Erlang Factory 2009&lt;br /&gt;(&lt;a href="http://video.yahoo.com/watch/5411131/14253846"&gt;video&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Interview at QCon 2008&lt;/span&gt;&lt;br /&gt;(&lt;a href="http://www.infoq.com/interviews/simon-peyton-jones-about-mainstream-programming-languages"&gt;video&lt;/a&gt;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-1506563064668096597?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/1506563064668096597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=1506563064668096597' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/1506563064668096597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/1506563064668096597'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/03/speaker-spotlight-simon-peyton-jones.html' title='Speaker Spotlight - Simon Peyton-Jones'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-8905818328237609136</id><published>2008-03-01T21:39:00.000-08:00</published><updated>2008-03-01T22:30:00.021-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='pattern matching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='arc'/><category scheme='http://www.blogger.com/atom/ns#' term='metaprogramming'/><category scheme='http://www.blogger.com/atom/ns#' term='syntax'/><category scheme='http://www.blogger.com/atom/ns#' term='macros'/><title type='text'>Haskell Style Pattern Matching In Arc</title><content type='html'>Since I did the &lt;a href="http://cadrlife.blogspot.com/2008/01/fluent-interface-grammars-part-i.html"&gt;Fluent Interface&lt;/a&gt; saga, it's only fair that I try to push the boundaries of metaprogramming in language that actually &lt;i&gt;has&lt;/i&gt; metaprogramming.&lt;br /&gt;&lt;br /&gt;Consider the following Haskell code. We will be striving to imitate it as closely as possible using an &lt;a href="http://arclanguage.org/"&gt;Arc&lt;/a&gt; macro.&lt;br /&gt;&lt;pre&gt;union xs [] = xs&lt;br /&gt;union [] ys = ys&lt;br /&gt;union xs@(x:xt) ys@(y:yt) | x &lt; y = x : union xt ys&lt;br /&gt;                          | y &lt; x = y : union xs yt&lt;br /&gt;                          | otherwise = x : union xt yt&lt;/pre&gt;First we will see how this function might traditionally be written.&lt;br /&gt;&lt;pre&gt;(def union (&lt; xs ys)&lt;br /&gt;  (if (no xs) ys&lt;br /&gt;      (no ys) xs&lt;br /&gt;      (with (x (car xs) xt (cdr xs)&lt;br /&gt;             y (car ys) yt (cdr ys))&lt;br /&gt;        (if (&lt; x y) (cons x (union &lt; xt ys))&lt;br /&gt;            (&lt; y x) (cons y (union &lt; xs yt))&lt;br /&gt;                    (cons x (union &lt; xt yt))))))&lt;/pre&gt;As a useful side-note, Arc's &lt;span style="font-style:italic;"&gt;let&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;with&lt;/span&gt; forms come with destructuring. This can save us a whole line here, as well as make the code more readable (no more cryptic &lt;span style="font-style:italic;"&gt;car&lt;/span&gt;s and &lt;span style="font-style:italic;"&gt;cdr&lt;/span&gt;s).&lt;br /&gt;&lt;pre&gt;(def union (&lt; xs ys)&lt;br /&gt;  (if (no xs) ys&lt;br /&gt;      (no ys) xs&lt;br /&gt;      (with ((x . xt) xs (y . yt) ys)&lt;br /&gt;        (if (&lt; x y) (cons x (union &lt; xt ys))&lt;br /&gt;            (&lt; y x) (cons y (union &lt; xs yt))&lt;br /&gt;                    (cons x (union &lt; xt yt))))))&lt;/pre&gt;This isn't bad. If we were programming in the wild, we would leave well enough alone at this point. However, this is an experiment; we want it to look Haskellian, not Lispy.&lt;br /&gt;&lt;br /&gt;We'll start with &lt;a href="http://arclanguage.org/item?id=3304"&gt;pcase&lt;/a&gt; a 10-line macro using &lt;a href="http://arclanguage.org/item?id=2556"&gt;almkglor's pattern matching library&lt;/a&gt; to yield something similar to Scala's match-case statement.&lt;br /&gt;&lt;pre&gt;(def union (&lt; xs ys)&lt;br /&gt;  (pcase `(,xs ,ys)&lt;br /&gt;    (xs ()) xs&lt;br /&gt;    (() ys) ys&lt;br /&gt;    ((x . xt) (y . yt))&lt;br /&gt;      (if (&lt; x y) (cons x (union &lt; xt ys))&lt;br /&gt;          (&lt; y x) (cons y (union &lt; xs yt))&lt;br /&gt;                  (cons x (union &lt; xt yt)))))&lt;/pre&gt;Switching from &lt;span style="font-style:italic;"&gt;pcase&lt;/span&gt; to &lt;span style="font-style:italic;"&gt;hcase&lt;/span&gt;, the outer parens in the patterns go away and equals signs separate the patterns from their corresponding expressions.&lt;br /&gt;&lt;pre&gt;(def union (&lt; xs ys)&lt;br /&gt;  (hcase `(,xs ,ys)&lt;br /&gt;    xs () = xs&lt;br /&gt;    () ys = ys&lt;br /&gt;    (x . xt) (y . yt) =&lt;br /&gt;      (if (&lt; x y) (cons x (union &lt; xt ys))&lt;br /&gt;          (&lt; y x) (cons y (union &lt; xs yt))&lt;br /&gt;                  (cons x (union &lt; xt yt)))))&lt;/pre&gt;To bring more Haskell syntax into the mix, we want to be able to substitute [] for () and (x:xt) for (x . xt). The colon and the brackets have special meanings in Arc, but our macro can intercept them without too much difficulty.&lt;br /&gt;&lt;pre&gt;(def union (&lt; xs ys)&lt;br /&gt;  (hcase `(,xs ,ys)&lt;br /&gt;    xs [] = xs&lt;br /&gt;    [] ys = ys&lt;br /&gt;    (x:xt) (y:yt) = &lt;br /&gt;      (if (&lt; x y) (cons x (union &lt; xt ys))&lt;br /&gt;          (&lt; y x) (cons y (union &lt; xs yt))&lt;br /&gt;                  (cons x (union &lt; xt yt)))))&lt;/pre&gt;Next, we can replace that pesky &lt;i&gt;if&lt;/i&gt; statement with guard clauses.&lt;br /&gt;&lt;pre&gt;(def union (&lt; xs ys)&lt;br /&gt;  (hcase `(,xs ,ys)&lt;br /&gt;    xs [] = xs&lt;br /&gt;    [] ys = ys&lt;br /&gt;    (x:xt) (y:yt) / (&lt; x y)   = (cons x (union &lt; xt ys))&lt;br /&gt;                  / (&lt; y x)   = (cons y (union &lt; xs yt))&lt;br /&gt;                  / otherwise = (cons x (union &lt; xt yt))))&lt;/pre&gt;The a single pipe | character can't be used here for technical reasons, so we'll have to make due with a slash /. A double pipe || could be used just as easily.&lt;br /&gt;&lt;br /&gt;Since the guard conditions are enclosed on either side by / and =, we can make the outer parens optional. The xs@(x:xt) constructs known as "&lt;a href="http://www.haskell.org/tutorial/patterns.html"&gt;as-patterns&lt;/a&gt;" are the next addition. Having these as-patterns, we can define a simple macro to bring &lt;i&gt;hcase&lt;/i&gt; up to the level of function arguments. &lt;br /&gt;&lt;pre&gt;(mac hdef (name . body)&lt;br /&gt;  (let args (uniq)&lt;br /&gt;   `(def ,name ,args (hcase ,args ,@body))))&lt;br /&gt;&lt;br /&gt;(hdef union &lt;br /&gt;  _ xs [] = xs&lt;br /&gt;  _ [] ys = ys&lt;br /&gt;  &lt; xs@(x:xt) ys@(y:yt) / &lt; x y = (cons x (union &lt; xt ys))&lt;br /&gt;                        / &lt; y x = (cons y (union &lt; xs yt))&lt;br /&gt;                        / otherwise = (cons x (union &lt; xt yt)))&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;The result&lt;/span&gt;: Lo! In a dazzling display of &lt;a href="http://xkcd.com/319/"&gt;engineering hubris&lt;/a&gt;, a Lisp dialect is dragged kicking and screaming into Haskell-like syntax. If you dare, you can take look at &lt;a href="http://paste.lisp.org/display/56496"&gt;the definition of hcase&lt;/a&gt; in all its convoluted glory.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Implementation note&lt;/span&gt;: Like most Lisps, Arc would read '(x : xs) as a list of three symbols, but '(x:xs) has only one. In order to behave properly, &lt;span style="font-style:italic;"&gt;hcase&lt;/span&gt; must split apart the symbols in patterns: '(xs@(x:y:yt)) becomes '(xs @ (x : y : yt)) and so on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-8905818328237609136?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/8905818328237609136/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=8905818328237609136' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/8905818328237609136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/8905818328237609136'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/03/haskell-style-pattern-matching-in-arc.html' title='Haskell Style Pattern Matching In Arc'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-5141261158417172373</id><published>2008-02-16T13:29:00.000-08:00</published><updated>2008-02-16T15:32:14.826-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='prime numbers'/><category scheme='http://www.blogger.com/atom/ns#' term='arc'/><title type='text'>Doing Eratosthenes Justice</title><content type='html'>Yesterday I showed how to use some closures and macros to implement (very inefficient) lazy lists in Lisp. One of my examples produced an infinite list of prime numbers.&lt;br /&gt;&lt;br /&gt;BlueStorm quite correctly pointed out that it was O(n^2), while the classic sieve of Eratosthenes is O(n log n). Always up for a &lt;a href="http://xkcd.com/356/"&gt;challenge&lt;/a&gt;, I went ahead wrote a proper sieve.&lt;br /&gt;&lt;pre&gt;(def merge_ (xs ys)&lt;br /&gt;  (with (x (car_ xs) y (car_ ys))&lt;br /&gt;    (if (&lt; x y) (cons_ x (merge_ (cdr_ xs) ys))&lt;br /&gt;        (&gt; x y) (cons_ y (merge_ xs (cdr_ ys)))&lt;br /&gt;        (cons_ x (merge_ (cdr_ xs) (cdr_ ys))))))&lt;br /&gt;&lt;br /&gt;(def diff_ (xs ys)&lt;br /&gt;  (with (x (car_ xs) y (car_ ys))&lt;br /&gt;    (if (&lt; x y) (cons_ x (diff_ (cdr_ xs) ys))&lt;br /&gt;        (&gt; x y) (diff_ xs (cdr_ ys))&lt;br /&gt;        (diff_ (cdr_ xs) (cdr_ ys)))))&lt;br /&gt;&lt;br /&gt;(def merge-multiples (li)&lt;br /&gt;  (with (xs (car_ li) rest (cdr_ li))&lt;br /&gt;    (cons_ (car_ xs)&lt;br /&gt;           (merge_ (cdr_ xs) (merge-multiples rest)))))&lt;br /&gt;&lt;br /&gt;(def multiples (p) (map_ [* _ p] (count-from p)))&lt;br /&gt;&lt;br /&gt;(= primes &lt;br /&gt;  (cons_ 2 (cons_ 3 (cons_ 5 (diff_ (count-from 7) non-primes)))))&lt;br /&gt;&lt;br /&gt;(= non-primes (merge-multiples (map_ multiples primes)))&lt;/pre&gt;A typical optimization is to ignore multiples of 2, as follows.&lt;br /&gt;&lt;pre&gt;(def count-from-by (n by) (cons_ n (count-from-by (+ n by) by)))&lt;br /&gt;&lt;br /&gt;(def multiples (p) (map_ [* _ p] (count-from-by p 2)))&lt;br /&gt;&lt;br /&gt;(= primes&lt;br /&gt;  (cons_ 2 (cons_ 3 (cons_ 5 (diff_ (count-from-by 7 2) non-primes)))))&lt;br /&gt;&lt;br /&gt;(= non-primes (merge-multiples (map_ multiples (cdr_ primes))))&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-5141261158417172373?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/5141261158417172373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=5141261158417172373' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/5141261158417172373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/5141261158417172373'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/02/doing-eratosthenes-justice.html' title='Doing Eratosthenes Justice'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-1383020458247440942</id><published>2008-02-15T18:26:00.000-08:00</published><updated>2008-02-15T22:18:49.485-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='arc'/><title type='text'>Lazy Lists in Arc</title><content type='html'>No time for inflammatory ranting today. We're going to define lazy lists in Arc. (See also &lt;a href="http://ray.codezen.org/wiki/doku.php?id=lazy_lisp"&gt;CL version&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;The idea of adding lazy lists to Lisp dates back to &lt;span style="font-style:italic;"&gt;&lt;a href="http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR44"&gt;TR44&lt;/a&gt;:&lt;br /&gt;CONS should not Evaluate its Arguments&lt;/span&gt; (Daniel P. Friedman, 1976). Guy Steele discusses TR44 and other cool ideas in &lt;a href="http://video.google.com/videoplay?docid=-4633168320660258097"&gt;this talk&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In order to delay evaluation, the lazy cons will suspend its arguments in closures. These closures will be executed on first access, and the results stored.&lt;br /&gt;&lt;pre&gt;(mac wrap (a) `(fn () ,a))&lt;br /&gt;(def force (f) (wrap (f)))&lt;br /&gt;(mac cons_ (a b) `(cons (wrap ,a) (wrap ,b)))&lt;br /&gt;(def car_ (li) ((zap force (car li))))&lt;br /&gt;(def cdr_ (li) ((zap force (cdr li))))&lt;/pre&gt;Presto, we're done! Those are all the primitive we need. Now we'll just define some typical list utilities to using our new car_, cdr_, and cons_.&lt;br /&gt;&lt;pre&gt;(def filter (p li)&lt;br /&gt;  (if (no li) li&lt;br /&gt;      (p (car_ li)) (cons_ (car_ li) (filter p (cdr_ li)))&lt;br /&gt;      (filter p (cdr_ li))))&lt;br /&gt;&lt;br /&gt;(def map_ (f li)&lt;br /&gt;  (if (no li) li&lt;br /&gt;      (cons_ (f (car_ li)) (map_ f (cdr_ li)))))&lt;br /&gt;&lt;br /&gt;(def take (n li) &lt;br /&gt;  (if (&lt;= n 0) nil&lt;br /&gt;      (cons (car_ li) (take (- n 1) (cdr_ li)))))&lt;/pre&gt;With those, we can start playing with infinite lists. For starters, the natural numbers.&lt;br /&gt;&lt;pre&gt;(def count-from (n) (cons_ n (count-from (+ n 1))))&lt;br /&gt;&lt;br /&gt;(= naturals (count-from 1))&lt;br /&gt;&lt;br /&gt;(take 5 (filter odd naturals))   ; =&gt; (1 3 5 7 9)&lt;br /&gt;(take 5 (map_ [* _ 3] naturals)) ; =&gt; (3 6 9 12 15)&lt;/pre&gt;Now, the &lt;a href="http://xkcd.com/113/"&gt;primes&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;(def sieve (li)&lt;br /&gt;  (let p (car_ li)&lt;br /&gt;    (cons_ p (sieve (filter [&gt; (mod _ p) 0] (cdr_ li))))))&lt;br /&gt;&lt;br /&gt;(= primes (sieve (count-from 2)))&lt;/pre&gt;Holy 4-line prime number sieve, Batman!&lt;br /&gt;&lt;pre&gt;(take 10 primes)  ; =&gt; (2 3 5 7 11 13 17 19 23 29)&lt;/pre&gt;Here is the equivalent in Haskell (see also &lt;a href="http://haskell.org/haskellwiki/Prime_numbers"&gt;HaskellWiki&lt;/a&gt;.)&lt;br /&gt;&lt;pre&gt;primes = sieve [2..] where&lt;br /&gt;    sieve (p:xs) = p : sieve (filter (\x -&gt; x `mod` p &gt; 0) xs)&lt;/pre&gt;&lt;br /&gt;P.S. A multi-arg version of map_. I did the single argument version above because it is easier to follow.&lt;br /&gt;&lt;pre&gt;(def map_ (f . lists)&lt;br /&gt;  (if (some no lists) nil&lt;br /&gt;      (cons_ (apply f (map car_ lists))&lt;br /&gt;             (apply map_ f (map cdr_ lists)))))&lt;/pre&gt;P.P.S. &lt;span style="font-weight:bold;"&gt;Bonus&lt;/span&gt;: Fibonacci sequence.&lt;br /&gt;&lt;pre&gt;(= fibs (cons_ 1 (cons_ 1 (map_ + fibs (cdr_ fibs)))))&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-1383020458247440942?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/1383020458247440942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=1383020458247440942' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/1383020458247440942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/1383020458247440942'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/02/lazy-lists-in-arc.html' title='Lazy Lists in Arc'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-7323817060405904731</id><published>2008-02-06T14:26:00.000-08:00</published><updated>2008-02-09T13:28:01.603-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='COBOL'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Is Java the new COBOL? No.</title><content type='html'>I'll bash Java as much as the next guy, but when people start to throw around &lt;a href="http://www.google.com/search?q=%22java+is+the+new+cobol%22"&gt;the 'C' word&lt;/a&gt;, that's where I draw the line. Being compared to COBOL is kind of like being compared to &lt;a href="http://xkcd.com/261/"&gt;Hitler&lt;/a&gt;. As Dijkstra said in 1975: &lt;blockquote&gt;The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offence.&lt;/blockquote&gt; Would anyone say the same about Java with a strait face?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html"&gt;The Perils of Java Schools&lt;/a&gt; offers some of the harshest criticism of Java to receive widespread attention. What's the chief complaint? Java is too easy! I'm serious. Joel actually asserts that Java is not difficult enough for a college curriculum. He argues that C++, with its pointer-juggling headaches, is much better at weeding out lesser minds.&lt;br /&gt;&lt;br /&gt;This is such a bizarre thing to say that I hardly know where to start.&lt;br /&gt;&lt;br /&gt;First off, I went to &lt;a href="http://mst.edu/"&gt;MST&lt;/a&gt; (formerly UMR) where our CS department uses C++ and we're damn proud of it. Therefore, it is with a heavy heart that I admit the following: Yes, Java is easier, but that's not a bug, it's a feature! Making programming easier is a &lt;a href="http://www2.cddc.vt.edu/jargon/html/G/Good-Thing.html"&gt;Good Thing&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Second, there actually exist C++ programmers who don't understand recursion. Sad but true. It's even possible (albeit rare) to make it through my school's pointer minefield without being able to recurs your way out of a wet paper bag. Joel is just plain wrong to assume that there is a single "part of the brain" whose purpose is to grok pointers and recursion. Pointers and recursion are not the same. At all.&lt;br /&gt;&lt;br /&gt;I'll grant that someone who only knows Java is unlikely to understand pointers, but how bad is that really? Pointers don't help you think in higher levels of abstraction. They exist for the sole purpose of getting in your way. Other respectable languages without pointers include: Lisp, Python, Haskell, Ocaml, and Scala.&lt;br /&gt;&lt;br /&gt;Recursion is a completely different matter. Java and C++ both support recursion equally well (or equally poorly). If you don't understand recursion, you don't really understand functions/methods. Period.&lt;br /&gt;&lt;br /&gt;Let's assume for the moment that I'm done picking on Joel Spolsky. His real point is that schools should not water down their curriculum, and I absolutely agree. Self-respecting CS departments should fight to keep data structures, operating systems, language design, and graph theory. They should also continue to require calculus. This all has nothing to do with our petty programming language feuds. Despite what we C++ elitists would have you believe, C++ is not an academic language. It is a vocational one. Universities teach C++ because employers want that skill, not because they think it builds character.&lt;br /&gt;&lt;br /&gt;Still, in all of his anti-Java rhetoric, Joel &lt;span style="font-style:italic;"&gt;never&lt;/span&gt; (AFAIK) compared Java to COBOL. That would be hitting below the belt.&lt;br /&gt;&lt;br /&gt;What makes me rush to Java's defense all of the sudden? Mostly it's because I'm at home sick with a cold... but here is an equally good reason.&lt;br /&gt;&lt;pre&gt;IDENTIFICATION DIVISION.&lt;br /&gt;PROGRAM-ID. HELLO-WORLD.&lt;br /&gt;PROCEDURE DIVISION.&lt;br /&gt;MAIN.&lt;br /&gt;   DISPLAY 'Hello World'.&lt;br /&gt;   STOP RUN.&lt;br /&gt;&lt;/pre&gt;I can not and will not compare Java to &lt;span style="font-style:italic;"&gt;that&lt;/span&gt;. Let's look at another example, just to drive it home.&lt;br /&gt;&lt;pre&gt;x = y * 2;       // C, C++, Java&lt;br /&gt;$x = $y * 2;     #  Perl&lt;br /&gt;X = Y * 2        !  Fortran&lt;br /&gt;(set! x (* y 2)) ;  Scheme&lt;br /&gt;(= x (* y 2))    ;  Arc&lt;br /&gt;&lt;/pre&gt;These are all fairly reasonable ways to multiply &lt;span style="font-style:italic;"&gt;y&lt;/span&gt; by 2 and store the result in &lt;span style="font-style:italic;"&gt;x&lt;/span&gt;. How does it look in COBOL?&lt;br /&gt;&lt;pre&gt;MULTIPLY 2 BY Y GIVING X.&lt;br /&gt;&lt;/pre&gt;I can't even look at that without cringing. COBOL was a horrifically misguided attempt to blend pseudo-code with pseudo-English. Being a "business-oriented language", COBOL had syntax designed to appeal to the managers of 1960. Java was an effort to simplify and enhance C++, designed to appeal to the programmers of 1995.&lt;br /&gt;&lt;br /&gt;So remember: Java just &lt;span style="font-style:italic;"&gt;kinda&lt;/span&gt; sucks. COBOL &lt;span style="font-style:italic;"&gt;really really really really&lt;/span&gt; sucks. If COBOL were an ice cream flavor, it would be pralines and arsenic. If COBOL were the only programming language I could use, I would leave the field.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-7323817060405904731?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/7323817060405904731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=7323817060405904731' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/7323817060405904731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/7323817060405904731'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/02/is-java-new-cobol-no.html' title='Is Java the new COBOL? No.'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-803379809993562000</id><published>2008-02-03T13:24:00.000-08:00</published><updated>2008-02-06T08:09:05.330-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nicknames'/><category scheme='http://www.blogger.com/atom/ns#' term='linguistics'/><category scheme='http://www.blogger.com/atom/ns#' term='Noam Chomsky'/><title type='text'>Nicknames for Noam Chomsky</title><content type='html'>[NOTE: If you have something better to be doing, you might want to move along. This is not one of my useful or insightful posts.]&lt;br /&gt;&lt;br /&gt;This is part of an ongoing &lt;a href="http://xkcd.com/114/"&gt;battle&lt;/a&gt; between myself and my linguistic superior, &lt;a href="http://paxlego.blogspot.com/2008/02/generative-grammarian-by-any-other-name.html"&gt;Hannah&lt;/a&gt;.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Choam Nomsky&lt;/li&gt;&lt;li&gt;Chommers in Charge&lt;/li&gt;&lt;li&gt;Chomalicious&lt;/li&gt;&lt;li&gt;Noam-ero Uno&lt;/li&gt;&lt;li&gt;The Roaming Noam&lt;/li&gt;&lt;li&gt;Chomfoolery&lt;/li&gt;&lt;li&gt; Chernoambyl&lt;/li&gt;&lt;li&gt;Chomp Suey&lt;/li&gt;&lt;li&gt;Hong-Chom Phooey&lt;/li&gt;&lt;li&gt;Long-Chom Silver's&lt;/li&gt;&lt;li&gt;International House of Chomcakes&lt;/li&gt;&lt;li&gt;GNU Gnoam 2.20&lt;/li&gt;&lt;li&gt;Chomskeroony&lt;/li&gt;&lt;li&gt;ThelNoamious Monk&lt;/li&gt;&lt;li&gt;Everlasting Chomstopper&lt;/li&gt;&lt;li&gt;The Blue-Collar Lingustics Tour featuring Jeff Foxchomsky and Chomsky the Cable Guy&lt;/li&gt;&lt;li&gt;ENoamuel Chomstein&lt;/li&gt;&lt;li style="font-weight: bold;"&gt;Rikki-Tikki-Chomsky&lt;/li&gt;&lt;li&gt;Chomery Clinton&lt;/li&gt;&lt;li&gt;Barrack OChoma&lt;/li&gt;&lt;li&gt;Chom Edwards&lt;/li&gt;&lt;li&gt;Chom McCain&lt;/li&gt;&lt;li&gt;Mitt Chomney&lt;/li&gt;&lt;li&gt;Chom Knuth&lt;/li&gt;&lt;li&gt;Necronoamicon&lt;/li&gt;&lt;li&gt;H.P. Chomscraft&lt;/li&gt;&lt;li&gt;The Call of Cthulhomsky&lt;/li&gt;&lt;li&gt;Noamus Opperandi&lt;/li&gt;&lt;li&gt;Chubby Chomsker&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Fats Chomino&lt;/li&gt;&lt;li&gt;The Human Genoam Project&lt;/li&gt;&lt;li&gt;Istanbul (Not ChomstantiNoample)&lt;/li&gt;&lt;li&gt;Chompernicus&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Current score: Ray 32, Hannah 45&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Hannah&lt;/span&gt;: As a wise man once said: "It is not enough to succeed, one's friends must also fail."&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ray&lt;/span&gt;: Who said that? Chomfucious?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;P.S.&lt;/span&gt; I can see now that this will be a battle of truly astronoamical proportions!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-803379809993562000?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/803379809993562000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=803379809993562000' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/803379809993562000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/803379809993562000'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/02/nicknames-for-noam-chomsky.html' title='Nicknames for Noam Chomsky'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-2666163021863293263</id><published>2008-02-01T23:03:00.001-08:00</published><updated>2008-02-02T14:16:01.772-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='closures'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='dragons'/><title type='text'>The Functional Programming Apologist</title><content type='html'>There do exist &lt;a href="http://video.google.com/videoplay?docid=3727739741840340025"&gt;legitimate&lt;/a&gt; criticisms of functional programming (FP) concepts, just as there are reasonable criticisms of imperative style, procedural style, prolog-esk logic/constraint programming, and even our precious object-orientation. Still, as you might expect, the vast majority of the tomatoes hurled in the general direction of the FP community are totally absurd. Here are a couple &lt;span style="font-style: italic;"&gt;actual&lt;/span&gt; comments from various blogs. I am not giving the sources for obvious reasons, but you could probably find them in &lt;a href="http://www.google.com/search?q=%22functional+programming+sucks"&gt;Google&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;Imperative languages represent the straight line from point A to point B. They reflect the true nature of the beast. If you had to slay a dragon, would you try to convince another dragon to fight for you, or would you grab a damn weapon?&lt;/blockquote&gt;Yes, as a matter of fact, I WOULD get another &lt;a href="http://www.amazon.com/Compilers-Principles-Techniques-Alfred-Aho/dp/0201100886"&gt;dragon&lt;/a&gt; to fight for me. It's called abstraction! This is why we have programming languages in the first place, even though machine code "reflects the true nature of the beast". Does your CPU know what object orientation is? Unless you do all your structure and flow control using &lt;a href="http://xkcd.com/292/"&gt;GOTO&lt;/a&gt;, you are NOT reflecting the true nature of your beloved beast. Sorry to break the news.&lt;br /&gt;&lt;br /&gt;Here's another real gem. I see this sort of thing all the time.&lt;br /&gt;&lt;blockquote&gt;Closures in today's world are a "language geek" feature. Unless done extremely carefully and in a way that supports the various skill levels of developers, they end up being unusable and unsupportable by anything less than computer language savants. In their inherent obscurity and complexity, "language geek" style closures are about as anti-Java as you can get.&lt;/blockquote&gt;First off thanks for calling me a geek, I really didn't get enough of that growing up interested in computers. Imagine a time when Java didn't have generics. In other words, imagine Java 1 through 4. Java 5 generics &lt;a href="http://video.google.com/videoplay?docid=-4167170843018186532"&gt;evolved&lt;/a&gt; from the type classes in Haskell — a fringe  fancy-pants FP academic language if there ever was one. Some people (possibly the same ones) were saying:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-weight: bold;"&gt;Generics&lt;/span&gt; in today's world are a "language geek" feature. Unless done extremely carefully and in a way that supports the various skill levels of developers, they end up being unusable and unsupportable by anything less than computer language savants. In their inherent obscurity and complexity, "language geek" style &lt;span style="font-weight: bold;"&gt;generics&lt;/span&gt; are about as anti-Java as you can get.&lt;/blockquote&gt;I think I've made my point.&lt;br /&gt;&lt;br /&gt;But wait! Maybe I've been wrong all these years! Maybe generics and even anonymous inner classes are perfect additions to Java, but closures would be stepping &lt;span style="font-style: italic;"&gt;way&lt;/span&gt; over the line. After all, they are an FP concept and Java is OO. That's like the &lt;a href="http://en.wikipedia.org/wiki/Hatfield-McCoy_feud"&gt;Hatfields and the McCoys&lt;/a&gt; and the two would &lt;a href="http://www.scala-lang.org/"&gt;never mix&lt;/a&gt;. Could that really be the case? &lt;br /&gt;&lt;br /&gt;Let's see what James Gosling, the &lt;span style="font-weight: bold;"&gt;inventer of Java&lt;/span&gt;, said about it &lt;a href="http://blogs.sun.com/jag/entry/closures"&gt;just yesterday&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;There has been a lot of chatter about the closures proposal penned by Neal Gafter. And, in particular, whether or not I support it. I absolutely do. Java feels alive, not stuck in some chisel marks on stone tablets. Closures were left out of Java initially more because of time pressures than anything else. Closures, as a concept, are tried and true - well past the days of being PhD topics.&lt;/blockquote&gt;And don't even ask me what &lt;a href="http://library.readscheme.org/page1.html"&gt;Guy Steele&lt;/a&gt; would say about it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-2666163021863293263?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/2666163021863293263/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=2666163021863293263' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/2666163021863293263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/2666163021863293263'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/02/functional-programming-apologist.html' title='The Functional Programming Apologist'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-6721530430409254575</id><published>2008-01-29T15:52:00.000-08:00</published><updated>2008-02-02T16:12:17.096-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='paul graham'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='arc'/><category scheme='http://www.blogger.com/atom/ns#' term='scheme'/><title type='text'>Arc is out!</title><content type='html'>&lt;a href="http://arclanguage.org/"&gt;Arc&lt;/a&gt; has been released! Let the &lt;a href="http://xkcd.com/297/"&gt;hype&lt;/a&gt; commence.&lt;br /&gt;&lt;br /&gt;As of now, it requires &lt;a href="http://download.plt-scheme.org/mzscheme/v352.html"&gt;MzScheme version 352&lt;/a&gt;. There is also a patch for later versions.&lt;br /&gt;&lt;br /&gt;This first release has generated allot of controversy; Check &lt;a href="http://codeclimber.blogspot.com/2008/01/arc-wars.html"&gt;Ethan's blog&lt;/a&gt; for a hearty dose of perspective.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-6721530430409254575?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/6721530430409254575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=6721530430409254575' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/6721530430409254575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/6721530430409254575'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/01/arc-is-out.html' title='Arc is out!'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-4502325705769864199</id><published>2008-01-28T20:56:00.000-08:00</published><updated>2008-01-31T06:15:05.486-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='workplace'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='office space'/><title type='text'>Re: "Borrowing at 100% Interest"</title><content type='html'>Ethan Vizitei has a &lt;a href="http://codeclimber.blogspot.com/2008/01/borrowing-at-100-interest.html"&gt;post&lt;/a&gt; up about about the perils of being interrupted whilst hard at work. He makes some good points, so go read it. Go ahead, I'll wait...&lt;blockquote&gt;...&lt;/blockquote&gt;So as I was saying, he makes good points but he also invokes &lt;span style="font-style:italic;"&gt;math&lt;/span&gt;. Whenever someone on a blog invokes math to make a point about computer programming, it is healthy to be a tad skeptical. (Even if it's &lt;a href="http://steve-yegge.blogspot.com/2007/12/codes-worst-enemy.html"&gt;Steve Yegge&lt;/a&gt;. Even if it's &lt;a href="http://www.paulgraham.com/equity.html"&gt;Paul Graham&lt;/a&gt;.... hell, especially if it's &lt;a href="http://www.paulgraham.com/gh.html"&gt;Paul Graham&lt;/a&gt;.) In that spirit, here is some nitpicking about Ethan's assumptions.&lt;br /&gt;&lt;br /&gt;If they don't interrupt you now, then the question they need answered doesn't get addressed in a timely manner. That might &lt;span style="font-style:italic;"&gt;also&lt;/span&gt; mean lost productivity.&lt;br /&gt;&lt;br /&gt;If you aren't on break, you are in "the Zone" — all the time? Are you really in the Zone 6 hours a day? Aren't you ever &lt;a href="http://xkcd.com/303/"&gt;compiling&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;If you are interrupted for N minutes, Ethan assumes it takes &lt;i&gt;exactly&lt;/i&gt; N minutes to get back in, regardless of N. That's seems arbitrary.&lt;br /&gt;&lt;br /&gt;When you are spending the N minutes getting back into the Zone, is that all pure waste? I would imagine it's just normal work with a bit less momentum.&lt;br /&gt;&lt;br /&gt;Still, it is something to think about. Cheers!&lt;br /&gt;&lt;br /&gt;P.S. And by "something to think about" I mean to say that Ethan's conclusion is more or less correct. It is only his reasoning that is a bit flawed. There's no doubt that interruptions do waste valuable time. I also think the best reason to avoid interrupting people is &lt;span style="font-weight:bold;"&gt;they don't like it&lt;/span&gt;. Particularly not Ethan (or Dan). However, "Borrowing at 100% interest" is a much more compelling title than "Hey, that's kind of annoying!"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-4502325705769864199?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/4502325705769864199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=4502325705769864199' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/4502325705769864199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/4502325705769864199'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/01/re-borrowing-at-100-interest.html' title='Re: &quot;Borrowing at 100% Interest&quot;'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-2978939721634395364</id><published>2008-01-14T04:47:00.000-08:00</published><updated>2008-01-21T11:16:45.258-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linguistics'/><category scheme='http://www.blogger.com/atom/ns#' term='java tricks'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='fluent interfaces'/><title type='text'>Fluent Interface Grammars: Part III (Nesting)</title><content type='html'>Last time, we saw the properties of fluent interfaces that use method-chaining only. Namely, they can express any regular language not containing the empty string. We also saw an example of a non-regular language. The language accepts any string with a run of a's followed by an equal number of b's, i.e. ab, aabb, aaabbb, etc...&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;S ::= a B&lt;br /&gt;S ::= a S B&lt;br /&gt;B ::= b&lt;br /&gt;&lt;/blockquote&gt;Today, in Part III of our saga, we examine fluent interfaces that use &lt;span style="font-style: italic;"&gt;nesting&lt;/span&gt; exclusively (Steve Asher discusses nested interfaces &lt;a href="http://buildwithoutboundaries.blogspot.com/2007/12/fluent-api-pattern-nested-interfaces.html"&gt;here&lt;/a&gt;). Just as one cannot implement this language as chaining interface,&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;a().b()&lt;br /&gt;a().a().b().b()&lt;br /&gt;a().a().a().b().b().b()   // (Can't do this.)&lt;br /&gt;&lt;/blockquote&gt;the most obvious nested interface for this language is also impossible, for similar reasons.&lt;blockquote&gt;&lt;br /&gt;a(b())&lt;br /&gt;a(a(b(b())))&lt;br /&gt;a(a(a(b(b(b()))))) // (Can't do this either.)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;However, it is quite easy to express this (slightly uglier) version:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;a(b())&lt;br /&gt;a(a(b()),b())&lt;br /&gt;a(a(a(b()),b()),b()) // (Yucky, but possible.)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;This is done with the following nested interface.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public static class S {}&lt;br /&gt;public static class B {}&lt;br /&gt;public static S a(B arg1) { return new S(); }&lt;br /&gt;public static S a(S arg1, B arg2) { return new S(); }&lt;br /&gt;public static B b() { return new B(); }&lt;br /&gt;&lt;/pre&gt;Thus, we find that there exists at least one non-regular language expressible with nested interfaces. What else can we do?&lt;br /&gt;&lt;br /&gt;All context-free grammars can be reduced to &lt;a href="http://en.wikipedia.org/wiki/Greibach_normal_form"&gt;Greibach normal form&lt;/a&gt;, which only allows production rules of two types:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;1. S ::= $&lt;br /&gt;2. A ::= a X&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;... where A is any non-terminal, a is any terminal, and X is a list of zero or more non-terminals. Rules of type 1 cannot be expressed because our grammars cannot accept the empty string (as noted in Part II). The rules of type 2 become top-level methods in this fashion:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// A ::= a&lt;br /&gt;public static A a() {return new A();}&lt;br /&gt;// A ::= a B&lt;br /&gt;public static A a(B arg1) {return new A();}&lt;br /&gt;// A ::= a BCD&lt;br /&gt;public static A a(B arg1, C arg2, D arg3) {return new A();}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Does this mean that any context-free grammar (that doesn't accept the empty string) can be mapped to a nested fluent interface? Not quite—there is one more caveat. No two rules may have the same right-hand side, because they would yield two top-level methods with competing signatures. The question then becomes: Can any context-free grammar be reduced to a Greibach normal form without duplicate right-hand sides? After afew minutes on a whiteboard, I'm leaning toward no.&lt;br /&gt;&lt;br /&gt;Let us now extend our grammar notation to indicate parameter lists.&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;S ::= a(B)&lt;br /&gt;S ::= a(S B)&lt;br /&gt;B ::= b()&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;This will make the transition from grammar to code more obvious. Additionally, it will prepare us for the &lt;a href="http://xkcd.com/365/"&gt;next&lt;/a&gt; chapter: mixed interfaces.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-2978939721634395364?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/2978939721634395364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=2978939721634395364' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/2978939721634395364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/2978939721634395364'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/01/fluent-interface-grammars-part-iii.html' title='Fluent Interface Grammars: Part III (Nesting)'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-3802563302365780093</id><published>2008-01-12T16:31:00.000-08:00</published><updated>2008-09-07T09:40:35.212-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linguistics'/><category scheme='http://www.blogger.com/atom/ns#' term='java tricks'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='fluent interfaces'/><title type='text'>Fluent Interface Grammars: Part II (Chaining)</title><content type='html'>Today's episode focuses on the grammars achievable using only method-chaining (as opposed to nesting). For brevity, we shall refer to this type of fluent interface as a chaining interface. See &lt;a href="http://laribee.com/blog/2007/07/12/ordered-fluency/"&gt;Ordered Fluency&lt;/a&gt; by David Laribee for an interesting discussion of chaining interfaces and their grammars.&lt;br /&gt;&lt;br /&gt;Before we get started, here are some &lt;a href="http://xkcd.com/214/"&gt;Wikipedia&lt;/a&gt; links that may come in handy.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Grammar_%28formal_language_theory%29"&gt;Grammar(formal language theory)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form"&gt;Backus-Naur form&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Chomsky_hierarchy"&gt;Chomsky hierarchy&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Context-free_grammar"&gt;Context-free grammar&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Regular_grammar"&gt;Regular Grammar&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Recall the Chomsky hierarchy:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Type-0, unrestricted grammars&lt;/li&gt;&lt;li&gt;Type-1, context-sensitive grammars&lt;/li&gt;&lt;li&gt;Type-2, context-free grammars&lt;/li&gt;&lt;li&gt;Type-3, regular grammars&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;There is more or less a one-to-one correspondence between chained interfaces and regular grammars. A regular grammar is expressed using only rules of these forms:&lt;br /&gt;&lt;blockquote&gt;A ::= a&lt;br /&gt;A ::= a B&lt;br /&gt;A ::= $&lt;/blockquote&gt;&lt;br /&gt;These are actually called "right regular grammars", but left regular grammars are equivalent in terms of the languages they can express. This regular grammar (with start symbol S) expresses the language consisting of all strings with a run of a's followed by a run of b's.&lt;br /&gt;&lt;blockquote&gt;S ::= a S | a B&lt;br /&gt;B ::= b | b B&lt;/blockquote&gt;&lt;br /&gt;The grammar accepts strings such as "aaab" and "abbbbb". Thus, a corresponding chaining interface would accept these chains.&lt;br /&gt;&lt;pre&gt;a().a().a().b()&lt;br /&gt;a().b().b().b().b().b()&lt;/pre&gt;&lt;br /&gt;What does it mean to say an interface &lt;span style="font-style: italic;"&gt;accepts&lt;/span&gt; a particular chain? Two conditions must hold: the statement must be a valid Java expression, and it must evaluate to the type of grammar's start symbol. In other words, these statements must compile:&lt;br /&gt;&lt;pre&gt;S statement = a().a().a().b();&lt;br /&gt;S statement = a().b().b().b().b().b();&lt;/pre&gt;This grammar is easily implemented in few classes:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Foo {&lt;br /&gt;   public static void main() {&lt;br /&gt;       S s1 = a().a().b().b().b();&lt;br /&gt;       S s2 = a().a().a().a().b();&lt;br /&gt;   }&lt;br /&gt;   public static class S {}&lt;br /&gt;   public static A a() { return new A(); }&lt;br /&gt;   public static class A {&lt;br /&gt;       public A a() { return new A(); }&lt;br /&gt;       public B b() { return new B(); }&lt;br /&gt;   }&lt;br /&gt;   public static class B extends S {&lt;br /&gt;       public B b() { return new B(); }&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Ok, so we've seen that a painfully simple regular grammar does indeed have a chaining interface counterpart. The real question is: How can we get from the grammar to the interface? After all, a richer grammar would not be so intuively simple to translate! With that in mind, here are the steps that will translate an arbitrary regular grammar into a chaining interface. As usual, S is assumed to be the start symbol.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Left factor the grammar.&lt;/li&gt;&lt;li&gt;Make a class for each non-terminal.&lt;/li&gt;&lt;li&gt;Rules with left-hand side S become static methods.&lt;/li&gt;&lt;li&gt;Rule with empty string ($) as their right-hand side make the class of their left-hand extend S.&lt;/li&gt;&lt;li&gt;All other rules are methods of their respective classes.&lt;/li&gt;&lt;/ol&gt;Rules can become methods in three ways:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Rules of form "A ::= a" become a method named a() in class A returning S.&lt;/li&gt;&lt;li&gt;Rules of form "A ::= a B" become a method named a() in class A returning B.&lt;/li&gt;&lt;li&gt;Rules with left-hand side S follow the same rules, but yield static methods.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Yikes, that sounds pretty complicated. Well, here goes nothing! First let us left factor our grammar, taking care to preserve its regular status.&lt;br /&gt;&lt;blockquote&gt;S ::= a S | a B&lt;br /&gt;B ::= b | b B&lt;/blockquote&gt;becomes&lt;br /&gt;&lt;blockquote&gt;S ::= a A&lt;br /&gt;A ::= a A | b B&lt;br /&gt;B ::= $ | b B&lt;/blockquote&gt;Good. Now, all the non-terminals (S, A, and B) will become classes. S will be empty as always, and we can also see that B will extend S. Next, we translate each rule into a method.&lt;br /&gt;&lt;pre&gt;// Top-level:&lt;br /&gt;public static A a() { return new A(); } // S ::= a A&lt;br /&gt;&lt;br /&gt;// In class A:&lt;br /&gt;public A a() { return new A(); } // A ::= a A&lt;br /&gt;public B b() { return new B(); } // A ::= b B&lt;br /&gt;&lt;br /&gt;// In class B:&lt;br /&gt;public B b() { return new B(); } // B ::= b B&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This yields code identical to the implementation above. The same can be done for any regular grammar - with one little tiny exception. Grammars that accept the empty string cannot be encoded in this way because "S statement = ;" would never be legal in Java. This is just a technicality however, because there isn't much of an outcry for fluent interfaces that accept &lt;span style="font-style: italic;"&gt;nothing&lt;/span&gt; as a statement.&lt;br /&gt;&lt;br /&gt;We have shown that (nearly) any regular language can be implemented as a fluent interface using only method chaining. Conversely, non-regular languages cannot be; not proven here, but happens to be true.&lt;br /&gt;&lt;br /&gt;Consider the prototypical example of a non-regular language. The language accepts any string with a run of a's followed by an equal number of b's, i.e. ab, aabb, aaabbb, etc...&lt;br /&gt;&lt;blockquote&gt;S ::= a B&lt;br /&gt;S ::= a S B&lt;br /&gt;B ::= b&lt;/blockquote&gt;It is &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; possible to write an interface that would accept only such chains as these:&lt;br /&gt;&lt;pre&gt;a().b()&lt;br /&gt;a().a().b().b()&lt;br /&gt;a().a().a().b().b().b() // and so on...&lt;/pre&gt;If you aren't convinced, I would invite you to try it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Update&lt;/span&gt;: That last statement technically wrong. Using generics (fair game, I said Java 5), &lt;a href="http://coding-exercises.blogspot.com"&gt;tkr&lt;/a&gt; accepted my invitation and indeed constructed this language. The parameterization trick he discovered doesn't seem applicable to context-free grammars in general, but is worth checking out nevertheless.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-3802563302365780093?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/3802563302365780093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=3802563302365780093' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/3802563302365780093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/3802563302365780093'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/01/fluent-interface-grammars-part-ii.html' title='Fluent Interface Grammars: Part II (Chaining)'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-5422094695660941623</id><published>2008-01-07T00:08:00.000-08:00</published><updated>2008-01-07T02:50:29.504-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linguistics'/><category scheme='http://www.blogger.com/atom/ns#' term='java tricks'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='fluent interfaces'/><title type='text'>Fluent Interface Grammars: Part I</title><content type='html'>A spectre is looming over the world of object-oriented design patterns—the spectre of fluent interfaces.&lt;br /&gt;&lt;br /&gt;This new and unorthodox style has been espoused by such giants as &lt;a href="http://martinfowler.com/bliki/FluentInterface.html"&gt;Martin Fowler&lt;/a&gt;, such average-heighted people as &lt;a href="http://buildwithoutboundaries.blogspot.com/"&gt;Steve Asher&lt;/a&gt;, and such midgets as &lt;a href="http://finneycanhelp.blogspot.com/2007/12/fluent-interfaces-domain-specific.html"&gt;Mike Finney&lt;/a&gt;. Knowing my place in the order of things, I suppose it is my turn. I'll start out by reiterating some of points being made.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fluent interfaces are a rockin' way to approximate the flexibility of domain specific languages (DSLs) using OO constructs.&lt;/li&gt;&lt;li&gt;Fluent interfaces are easy to use, but relatively difficult to design.&lt;/li&gt;&lt;li&gt;Fluent interfaces violate several "best practices" of interface design (such as command query separation), but are often a Good Thing nevertheless.&lt;/li&gt;&lt;li&gt;If Sun finally gives us &lt;a href="http://library.readscheme.org/page1.html"&gt;closures&lt;/a&gt; in &lt;a href="https://jdk7.dev.java.net/"&gt;Java 7&lt;/a&gt;, the skys will part, the rapture will be upon us, and we will all join hands singing "Camptown Races". Also, fluent interfaces will become cooler.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;As everyone keeps pointing out, a fluent interface resembles a sort of domain specific language. I would like to explore how far that analogy goes. In other words, what are the limitations on the languages that fluent interfaces can provide? Michael Feathers asks essentially the same question in &lt;a href="http://beautifulcode.oreillynet.com/2007/12/the_cardinality_of_a_fluent_in.php"&gt;The Cardinality of a Fluent Interface&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;What qualities does a grammar need to have to create an embedded DSL which doesn’t allow nonsensical constructs?&lt;/blockquote&gt;&lt;br /&gt;Before addressing this problem, let us set some ground rules. First, we live in Java 5. Second, it is not sufficient for our interface to accept some superset of the desired language; our grammar must be an exact fit. Ungrammatical statements must not compile. They should also be underlined by our spiffy IDE :)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Note&lt;/span&gt;: In formal language theory, a &lt;a style="font-style: italic;" href="http://en.wikipedia.org/wiki/Formal_grammar"&gt;grammar&lt;/a&gt; is a set of transformation rules and a &lt;span style="font-style: italic;"&gt;language&lt;/span&gt; is the set of all &lt;a href="http://xkcd.com/171/"&gt;strings&lt;/a&gt; that the grammar accepts. Some background with these concepts is assumed.&lt;br /&gt;&lt;br /&gt;Fluent interfaces generally use two ways of combining tokens to form statements: &lt;span style="font-style: italic;"&gt;Call-chaining&lt;/span&gt; as().seen().here(), and &lt;span style="font-style: italic;"&gt;nesting&lt;/span&gt; which(works(like(so))). Some interfaces stick to one or the other, while Steve's customer creator uses both:&lt;br /&gt;&lt;pre&gt;Customer customer = &lt;br /&gt;createCustomer.named("Bob").that(bought.item(CompactDisc).on("02/17/2006"));&lt;/pre&gt;He explains,&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The first thing to notice is that almost half of this code is fully enclosed in parenthesis. The result of 'bought.item(CompactDisc).on("02/17/2006")' is being passed to a method named 'that'.&lt;/blockquote&gt;&lt;br /&gt;By contrast, this is what that statement would look like using call-chaining all the way:&lt;pre&gt;Customer customer = &lt;br /&gt;createCustomer.named("Bob").that().bought().item(CompactDisc).on("02/17/2006");&lt;/pre&gt;And here is one of the possible translations using only nesting:&lt;pre&gt;Customer customer = &lt;br /&gt;createCustomer(named("Bob",that(bought(item(CompactDisc,on("02/17/2006"))))));&lt;/pre&gt;&lt;br /&gt;The customer creator's grammar would look similar to this.&lt;br /&gt;&lt;pre&gt;S ::= createCustomer C&lt;br /&gt;C ::= $&lt;br /&gt;C ::= namedSomething C&lt;br /&gt;C ::= that T C&lt;br /&gt;C ::= and  T C&lt;br /&gt;T ::= bought someItem&lt;br /&gt;T ::= bought someItem onSomeDate&lt;/pre&gt;Examples of strings accepted by this grammar:&lt;pre&gt;createCustomer&lt;br /&gt;createCustomer namedSomething&lt;br /&gt;createCustomer namedSomething that bought someItem&lt;br /&gt;createCustomer that bought someItem and bought someItem onSomeDate&lt;/pre&gt;So far I have introduced the idea of formal grammars for fluent interfaces, and posed a question about their limitations. In future posts I will answer this question for each variant of fluent interfaces: call-chaining, nesting, and mixed. Have faith! I am going somewhere with this.&lt;br /&gt;&lt;br /&gt;P.S. Steve and Mike: I was just kidding, you are both well above average height.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-5422094695660941623?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/5422094695660941623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=5422094695660941623' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/5422094695660941623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/5422094695660941623'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2008/01/fluent-interface-grammars-part-i.html' title='Fluent Interface Grammars: Part I'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-4292206306728808583</id><published>2007-12-31T02:35:00.000-08:00</published><updated>2007-12-31T05:56:11.066-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='nerdcore'/><category scheme='http://www.blogger.com/atom/ns#' term='ray&apos;s stupid jokes'/><title type='text'>So much drama in the PHP</title><content type='html'>According to &lt;a href="http://www.google.com/search?q=%22so+much+drama+in+the+php%22"&gt;Google&lt;/a&gt;, as of 4am, December 31st, 2007: I am the first person on the internet to say "So much drama in the PHP!" &lt;a href="http://xkcd.com/301"&gt;First post&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Unfortunately (or perhaps fortunately), I haven't used PHP much, so I have no PHP stories to tell here. If you do, feel free to leave a comment or even make your own little "Drama in the the PHP" blog post!&lt;br /&gt;&lt;br /&gt;To explain: This is a pun on "So much drama in the PhD," replacing the idea of working through a &lt;a href="http://www.phdcomics.com/comics.php"&gt;PhD&lt;/a&gt; program with that of programming in the language &lt;a href="http://www.php.net/"&gt;PHP&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In case you're not up on &lt;a href="http://en.wikipedia.org/wiki/Nerdcore"&gt;nerdcore&lt;/a&gt;, "So much drama in the PhD" was the clever if poorly delivered debut by Monzy, in which he attacked "established" nerdcore artist MC Plus+. For the record, MC Plus+ had it coming.&lt;br /&gt;&lt;br /&gt;Of course, the title of "So much drama in the PhD" was an homage to the first line of Snoop Dogg's classic song "Gin and Juice" from the 1993 album &lt;span style="font-style: italic;"&gt;Doggystyle&lt;/span&gt;.&lt;br /&gt;&lt;blockquote&gt;With so much drama in the L-B-C&lt;br /&gt;It's kinda hard bein Snoop D-O-double-G&lt;/blockquote&gt;&lt;br /&gt;Most agree that LBC refers to Long Beach, California - though some suggest that the intent may be Long Beach City, or even Long Beach/Compton.&lt;br /&gt;&lt;br /&gt;On a related note, all you people who have have files on your iPod called "&lt;span style="font-style: italic;"&gt;Blues Travelers - Gin and Juice (with Dave Mathews Band)(1).mp3&lt;/span&gt;", CHANGE THEM! It's not Blues Traveler. It's not Dave Mattews Band. It's NOT Phish. That cover is done by &lt;a href="http://www.youtube.com/watch?v=SunrKwykK_Y"&gt;The Gourds&lt;/a&gt;. I'm serious about it not being Phish. This is my serious face.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-4292206306728808583?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/4292206306728808583/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=4292206306728808583' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/4292206306728808583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/4292206306728808583'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2007/12/so-much-drama-in-php.html' title='So much drama in the PHP'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2280966215016131075.post-5813338867152945755</id><published>2007-12-30T04:01:00.000-08:00</published><updated>2007-12-30T04:42:48.253-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mikefinney'/><category scheme='http://www.blogger.com/atom/ns#' term='trends'/><category scheme='http://www.blogger.com/atom/ns#' term='blogging'/><title type='text'>How I decided it was time to get a blog</title><content type='html'>The other day I was at work, minding my own business as I often do, when my esteemed co worker &lt;a href="http://www.michaelfinney.com/"&gt;Mike Finney&lt;/a&gt; began searching the Internet for my blog -- or as we call them in the old country, my &lt;a href="http://xkcd.com/181/"&gt;blag-o-sphere&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This was an odd thing to be doing, for two reasons. First, I did not at the time even have a blog. Second, and perhaps more revealing, &lt;span style="font-style: italic;"&gt;I was sitting two feet from him&lt;/span&gt;. If he wanted to know my opinion on some esoteric topic, he could've turned oh-so-slightly to the right and said:&lt;br /&gt;&lt;br /&gt;"Hey Ray, how 'bout those embedded systems?"&lt;br /&gt;&lt;span style="font-style: italic;"&gt;or&lt;/span&gt;&lt;br /&gt;"Hey Ray, would you consider Java to be the new COBOL?"&lt;br /&gt;&lt;span style="font-style: italic;"&gt;or&lt;/span&gt;&lt;br /&gt;"Alotta people are referring to JavaScript as a sort of assembly language for the web. What's your take, Ray?"&lt;br /&gt;&lt;br /&gt;My answers, in no particular order, would've been "Yes," "No," and "I embedded your mom!" I find it hard to believe that someone who has been financially coerced into working around me would ever feel such a Ray's-opinion shortage as to require dipping into some electronic cache of my technical ramblings.&lt;br /&gt;&lt;br /&gt;Still, I must waist no time in addressing this famine! &lt;a href="http://finneycanhelp.blogspot.com/"&gt;Mike Finney&lt;/a&gt;, your prayers are answered. You will now have the privilege of disagreeing with me at any hour of the day or night.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2280966215016131075-5813338867152945755?l=cadrlife.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cadrlife.blogspot.com/feeds/5813338867152945755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2280966215016131075&amp;postID=5813338867152945755' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/5813338867152945755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2280966215016131075/posts/default/5813338867152945755'/><link rel='alternate' type='text/html' href='http://cadrlife.blogspot.com/2007/12/how-i-decided-it-was-time-to-get-blog.html' title='How I decided it was time to get a blog'/><author><name>Ray Myers</name><uri>http://www.blogger.com/profile/06848042365037213287</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://bp1.blogger.com/_Xk3k6lsmUxU/R-wzOSfimhI/AAAAAAAAAAk/ms2Glf0Av30/S220/pic.png'/></author><thr:total>3</thr:total></entry></feed>
