<?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'><id>tag:blogger.com,1999:blog-5819005</id><updated>2009-12-04T06:40:19.070-08:00</updated><title type='text'>Programming and politics</title><subtitle type='html'>Mostly technical and political -- stuff to bore everyone.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default?start-index=26&amp;max-results=25'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>606</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5819005.post-7636424102744343912</id><published>2009-11-24T13:39:00.000-08:00</published><updated>2009-11-24T13:39:44.327-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile web'/><category scheme='http://www.blogger.com/atom/ns#' term='web applications'/><category scheme='http://www.blogger.com/atom/ns#' term='desktop applications'/><title type='text'>Web Developers Are Stupid and Arrogant</title><content type='html'>The past couple of days has seen &lt;a href="http://www.quirksmode.org/blog/archives/2009/11/apple_is_not_ev.html"&gt;an amusing rant by PPK&lt;/a&gt;, that then turned into &lt;a href="http://www.quirksmode.org/blog/archives/2009/11/native_iphone_a.html"&gt;a retraction and call to action&lt;/a&gt;. The original rant included a condemnation of iPhone developers as being stupid and arrogant. &lt;a href="http://almaer.com/blog/iphone-developers-are-not-arrogant-and-stupid"&gt;Others&lt;/a&gt; have adequately refuted PPK, so I won't bother with any of that. His post made me realize that it is in fact web developers who are mostly commonly guilty of stupidity and arrogance. Here's what I mean.&lt;br /&gt;&lt;br /&gt;It's easy to look at the world today and say that web applications have won. This is web developer arrogance. Stupidity is to think that web applications have won because web applications are superior to desktop applications. Smarter, but probably still arrogant developers would point to web applications as &lt;a href="http://en.wikipedia.org/wiki/Disruptive_technology"&gt;disruptive technologies&lt;/a&gt;. This involves admitting that web applications are inferior, but good enough, and present enough other "cheaper" advantages to compensate for their inferiority.&lt;br /&gt;&lt;br /&gt;To understand why the "web apps have won" claim is dubious. There are definitely a lot of awesome web applications out there. Many of them were created back in the mid/late 90's, The "features" of these applications were the key to applications, not the user interface. Now these days, most of these web applications offer APIs/web services/RESTful interfaces/whatever you want to call them. In many cases it is possible to build desktop applications that tap into the same features as these web applications. However, this was certainly not the case 10-15 years ago.&lt;br /&gt;&lt;br /&gt;So if APIs make it possible to build desktop apps that offer the same features as popular web applications, why haven't people switched? The first most obvious answer is inertia. If you are used to accessing Google or Amazon on the web, that's probably the way that you will always use it. Something else to consider is that for many web applications, it does not make sense for them to offer all of their features through APIs because it hurts their core business. This is most obviously true for advertising based companies like Google, Yahoo, and Facebook. Their web applications not only provide very useful features to end users, but they serve ads that make money for the companies. If all of their users switched to using desktop applications that only offered the features with no ads, then the companies would lose their revenue streams. Their business is connected at the hip with their UI, so it is in their best interest to make sure people use their UI -- which is a web application.&lt;br /&gt;&lt;br /&gt;However, there are other very successful web applications whose main revenue does not come from ads. Their business is distinct from their UI. E-commerce companies like Amazon and my employer, eBay are obvious examples. For example, eBay offers &lt;a href="http://developer.ebay.com/products/trading/"&gt;trading APIs&lt;/a&gt; that provide almost all of the trading features of eBay. This is particularly true for selling on eBay. This makes sense, as eBay does not need a seller to use the eBay UI to sell something, as the UI is not what makes money for eBay. As a result, around 50% of all items for sale on eBay come through 3rd party applications built on top of the eBay trading APIs. The vast majority of these (especially the popular ones) are desktop applications. Give people a choice, and a lot of people choose desktop applications.&lt;br /&gt;&lt;br /&gt;For another interesting example, just look at Twitter. This is a company that came into an existence after web APIs had become the norm. So Twitter has provided a comprehensive set of APIs since early in its existence. Further, they have not pursued an advertising model that would marry their web based UI to any revenue streams. So they have kept their APIs in sync with their features. For example, they recently added list and retweet features to their site, and added them to the APIs at the same time. As a result, there are a huge number of desktop applications for accessing Twitter. Indeed, Twitter says that 80% of their traffic is from APIs -- either desktop or mobile applications. For most Twitter users, there have always been feature-equivalent desktop alternatives to Twitter's web based UI, so many users chose desktop applications over the web.&lt;br /&gt;&lt;br /&gt;Finally, let's look at one more example: existing desktop apps. There has been an incredible amount of money spent on creating web applications that provide similar functionality to traditional desktop applications: email, word processing, etc. Heck, Google has spent a lot in this space just by itself. These are useful applications, but it is rare for people to choose these apps over their desktop equivalents. In most cases these apps try to go the disruptive route, i.e. don't try to be as good, but good enough and cheaper. They have had little success so far. Of course, inertia is a valid argument here, too. The one case where there has been success is GMail. In my opinion its success is not because people like it's web UI over a desktop UI, or even that the web UI is "good enough" and cheaper. No, it's success is because it has offered innovative features over other web and desktop based alternatives: fast search, stars/labels, threaded conversations, etc. Even give all of that, many people still choose to use desktop clients to access their GMail (I'm definitely not one of them.) Anyways, once again it's the features, not the UI.&lt;br /&gt;&lt;br /&gt;I am not going to sit here and claim that desktop wins over web all the time. I'm not arrogant or stupid enough to make such claims. However, be wary of claims that web apps win over desktop apps. One could argue that with the preponderance of APIs (especially spurned on by mobile apps) and the popping of the advertising based web 2.0 bubble, that the future will hold even more opportunities for desktop alternatives to web applications. Maybe web applications have jumped the shark. So don't put up with web developers who insist that web applications have won (especially if they try to extrapolate this flawed argument to the mobile world). They can go on and on about technology, standards, interoperability, etc. Just remind them that it's the users who matter, and when given a choice, the users do not always choose web applications. Time to polish off your MFC and Cocoa skills!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-7636424102744343912?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/7636424102744343912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=7636424102744343912' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/7636424102744343912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/7636424102744343912'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/11/web-developers-are-stupid-and-arrogant.html' title='Web Developers Are Stupid and Arrogant'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-1441975679856658846</id><published>2009-11-21T22:30:00.000-08:00</published><updated>2009-11-21T22:30:34.328-08: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='jvm'/><title type='text'>Passing on the Duby</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.nparikh.org/pub/images/giant-doobie.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="386" src="http://www.nparikh.org/pub/images/giant-doobie.jpg" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Last week I had &lt;a href="http://www.bettween.com/headius/michaelg/conversation/1302403"&gt;a fun conversation with Charles Nutter&lt;/a&gt;. It was about "java.next" and in particular, Charlie's requirements for a true replacement for Java. He &lt;a href="http://twitter.com/headius/status/5671504509"&gt;stated his requirements&lt;/a&gt; slightly before that conversation, so let me recap:&lt;br /&gt;&lt;br /&gt;1.) Pluggable compiler&lt;br /&gt;2.) No runtime library&lt;br /&gt;3.) Statically typed, but with inference&lt;br /&gt;4.) Clean syntax&lt;br /&gt;5.) Closures&lt;br /&gt;&lt;br /&gt;I love this list. It is a short list, but just imagine if Java 7 was even close to this. Anyways, while I like the list as a whole, I strongly objected to #2 -- No runtime library. Now, I can certainly understand Charlie's objection to a runtime library. It is a lot of baggage to drag around. All of the JVM langs have this issue. JRuby for example, has an 8 MB jar. Groovy has a 4 MB jar. Clojure has two jars totaling 4.5 MB. Scala is also around 4 MB. These become a real issue if you want to use any of these languages for something like Android development. &lt;a href="http://www.ibm.com/developerworks/opensource/library/os-eclipse-scala/index.html"&gt;I've written about this issue&lt;/a&gt; as well.&lt;br /&gt;&lt;br /&gt;However, there is a major problem with this requirement. The building blocks of any programming language includes primitives and built-in types. Those built-in types are part of the runtime library of the language. So if your JVM based language cannot have a runtime library, then you will have to make do with primitives and Java's built-in types. Why is this so bad? Java's types (mostly) make sense in the context of Java, its design principles and syntax. I don't think they would make sense in the java.next hypothetical language described above. The easiest example of this are collection classes. Don't you want a list that can make use of closures (#5 requirement above) for things like map, reduce, filter, etc. ? Similarly, if you static typing, you probably have generics, and wouldn't you like some of your collections to be covariant? You can go even further and start talking immutability and persistent data structures, and all of the benefits these things bring to concurrent programming. This is just collections (though obviously collections are quite fundamental to any language,) but similar arguments apply to things like IO, threading, XML processing, even graphics (I'd like my buttons to work with closures for event handling thank you very much.)&lt;br /&gt;&lt;br /&gt;One argument against this is that you can just include the runtime library of your choice. Pick your own list, hash map, thread pool, and file handler implementations. This is what I'd like to call the C++ solution -- only worse. At least in C++ you can generally count on the STL being available. The thing that is so bad about this is that it really limits the higher-order libraries that can be built. Java, Ruby, and Python all have a plethora of higher order libraries that have been built and widely used. These libraries make extensive use of the built-in types of those languages. Imagine building ORMs like Hibernate or ActiveRecord if you did not have built-in types (especially collection classes) that were consistent with the language. You could not do it. If all you could rely on was the Java built-in types, then at best your libraries would have a very Java-ish feel to them, and doesn't that defeat the purpose?&lt;br /&gt;&lt;br /&gt;Charlie gave an alternative to this -- leverage the compiler plugins. Now it is certainly true that with a pluggable compiler, you could do this like add a map method to the java.util.List interface, and all of the JDK classes that implement this interface. It can be done. However, if you are going to build higher order libraries on top of this language, then you need to be able to count on these enhancements being present. In other words, the compiler plugin needs to be a required part of the compiler. Fine. Now what is it that we were trying to avoid? Extra runtime baggage, right? Well if you have a compiler that is going to enhance a large number of the classes in the JDK, hello baggage. Maybe it won't be as much baggage as 4 MB runtime library, but it might not be a lot less either. Also, it raises the potential problem of interoperability with existing Java libraries. If I import a Hibernate jar that gives me a java.util.List, that list is not going to be enhanced by my compiler -- because it wasn't compiled with my javac.next, it was compiled with javac.old. What's going to happen here?&lt;br /&gt;&lt;br /&gt;Now there is an obvious happy way to deal with the runtime library question: rt.jar. If java.next was Java, and the super revamped collections, IO, threading, etc. classes were part of the JDK, then there is no need for a runtime library since now it has been included with the JDK. However, given the incredibly uncertain state of Java 7, not to mention the long term prospects of Java, does this seem remotely possible to anyone? I don't think so. I think the heir apparent to Java cannot be Java, and I think because of that, it's gotta have a runtime library of its own.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-1441975679856658846?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/1441975679856658846/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=1441975679856658846' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/1441975679856658846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/1441975679856658846'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/11/passing-on-duby.html' title='Passing on the Duby'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-4745333253738328253</id><published>2009-11-16T22:22:00.000-08:00</published><updated>2009-11-16T22:22:32.910-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile web'/><category scheme='http://www.blogger.com/atom/ns#' term='geolocation'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Cross Browser Geolocation</title><content type='html'>You might have heard that &lt;a href="http://www.techcrunch.com/2009/11/11/joe-hewitt-developer-of-facebooks-massively-popular-iphone-app-quits-the-project/"&gt;Joe Hewitt has given Apple the finger&lt;/a&gt;, and is moving on (or more accurately moving back to) mobile web development. You can do a lot on mobile web browsers -- more than you can do on desktop browsers. This can seem counterintuitive at first. However, flavors of WebKit have a huge share of mobile web use, and it supports a lot of features that you can't count on in the IE-dominated world of desktop browsers. One of those coveted features is geolocation. However, geolocation support is far from standardized even among the high end WebKit based browsers.&lt;br /&gt;&lt;br /&gt;Geolocation on Mobile Safari is nice, or more accurately it is "standardized." It follows the W3C standard. All you have to do is access the navigator.geolocation object. Here is a super simple example:&lt;br /&gt;&lt;pre class="brush:js" name="code"&gt;var gps = navigator.geolocation;&lt;br /&gt;    if (gps){&lt;br /&gt;        gps.getCurrentPosition(successHandler);&lt;br /&gt;    } &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function successHandler(position){&lt;br /&gt;  var lat = position.coords.latitude;&lt;br /&gt;  var long = position.coords.longitude;&lt;br /&gt;  doSomethingUseful(lat, long);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Pretty easy, huh? This will work on Mobile Safari running on iPhone OS 3+. As mentioned, it is standard. It will also work on newer versions of Firefox, which presumably includes Mobile Firefox, a.k.a. &lt;a href="https://wiki.mozilla.org/Fennec"&gt;Fennec&lt;/a&gt;. However, that is the limit of the portability of this code. It will not work in Android's browser.&lt;br /&gt;Android's flavor of WebKit, does not support the standard. However, it does support geolocation via Google Gears. That's right, instead of supporting the open standard, it implements the same feature using a proprietary technology. Shocking, I know. So if you are going to run JS that should access geolocation on both the iPhone and one of the zillion Android phones out there, you will need to include the gears_init.js bootstrap file. Then you can re-write the above like this:&lt;br /&gt;&lt;pre class="brush:js" name="code"&gt;function load(){&lt;br /&gt;    var gps = navigator.geolocation;&lt;br /&gt;    if (gps){&lt;br /&gt;        gps.getCurrentPosition(successHandler);&lt;br /&gt;    } else {&lt;br /&gt;        if (window.google &amp;amp;&amp;amp; google.gears){&lt;br /&gt;            gps = google.gears.factory.create('beta.geolocation');&lt;br /&gt;            gps.getCurrentPosition(function (position){&lt;br /&gt;               successHandler({coords : position});&lt;br /&gt;            }) ;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function successHandler(position){&lt;br /&gt;  var lat = position.coords.latitude;&lt;br /&gt;  var long = position.coords.longitude;&lt;br /&gt;  doSomethingUseful(lat, long);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;So this is pretty close to the standard, but not quite. The Gears variant also supports the getCurrentPosition API. However, the object that it passes to the success function is different. It is a flatter structure. So in the above example, we wrap it inside another object so that we can reuse the same handler.&lt;br /&gt;I haven't tried the webOS browser, yet or the Nokia WebKit variant yet. Here's hoping they are close to the standard used by Safari.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-4745333253738328253?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/4745333253738328253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=4745333253738328253' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/4745333253738328253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/4745333253738328253'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/11/cross-browser-geolocation.html' title='Cross Browser Geolocation'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-7573175256535273851</id><published>2009-11-10T17:04:00.000-08:00</published><updated>2009-11-10T17:05:52.766-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='javaone'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><title type='text'>Clojures Primes Shootout</title><content type='html'>Back in May, I was working on my &lt;a href="http://fupeg.blogspot.com/2009/06/javaone-talk-performance-comparisons-of.html"&gt;JavaOne talk on JVM language performance&lt;/a&gt;. The first comparison was a &lt;a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"&gt;prime number sieve&lt;/a&gt;. If you look back at the slides, you might notice that I did not include a Clojure implementation. There were a couple of reasons for this. First, I was dumb. Not only dumb, but especially dumb when it came to Clojure. I had recently learned it -- mostly on an airplane to Israel earlier that month. Second, realizing that I was dumb, I was at least smart enough to reach out to the Clojure community for help. I got some great help on the other algorithms, but the prime sieve was unsatisfactory. The implementations I got were just too different from the algorithms used for the other languages, that it did not seem like a good comparison. I have been meaning to go back and come up with a satisfactory implementation. And before you ask, I know about &lt;a href="http://clj-me.cgrand.net/index.php?s=Primes"&gt;this blazingly fast one&lt;/a&gt;:&lt;br /&gt;&lt;pre name="code" class="brush:clj"&gt;(defn lazy-primes []&lt;br /&gt;  (letfn [(enqueue [sieve n step]&lt;br /&gt;            (let [m (+ n step)]&lt;br /&gt;              (if (sieve m)&lt;br /&gt;                (recur sieve m step)&lt;br /&gt;                (assoc sieve m step))))&lt;br /&gt;          (next-sieve [sieve candidate]&lt;br /&gt;            (if-let [step (sieve candidate)]&lt;br /&gt;              (-&gt; sieve&lt;br /&gt;                (dissoc candidate)&lt;br /&gt;                (enqueue candidate step))&lt;br /&gt;              (enqueue sieve candidate (+ candidate candidate))))&lt;br /&gt;          (next-primes [sieve candidate]&lt;br /&gt;            (if (sieve candidate)&lt;br /&gt;              (recur (next-sieve sieve candidate) (+ candidate 2))&lt;br /&gt;              (cons candidate&lt;br /&gt;                (lazy-seq (next-primes (next-sieve sieve candidate)&lt;br /&gt;                            (+ candidate 2))))))]&lt;br /&gt;    (cons 2 (lazy-seq (next-primes {} 3)))))&lt;br /&gt;&lt;/pre&gt;and &lt;a href="http://paste.lisp.org/display/69952"&gt;this one that is very close to what I wanted&lt;/a&gt;:&lt;br /&gt;&lt;pre name="code" class="brush:clj"&gt;(defn sieve [n]&lt;br /&gt;  (let [n (int n)]&lt;br /&gt;    "Returns a list of all primes from 2 to n"&lt;br /&gt;    (let [root (int (Math/round (Math/floor (Math/sqrt n))))]&lt;br /&gt;      (loop [i (int 3)&lt;br /&gt;             a (int-array n)&lt;br /&gt;             result (list 2)]&lt;br /&gt;        (if (&gt;= i n)&lt;br /&gt;          (reverse result)&lt;br /&gt;          (recur (+ i (int 2))&lt;br /&gt;                 (if (&amp;lt; i root)&lt;br /&gt;                   (loop [arr a&lt;br /&gt;                          inc (+ i i)&lt;br /&gt;                          j (* i i)]&lt;br /&gt;                     (if (&gt;= j n)&lt;br /&gt;                       arr&lt;br /&gt;                       (recur (do (aset arr j (int 1)) arr)&lt;br /&gt;                              inc&lt;br /&gt;                              (+ j inc))))&lt;br /&gt;                   a)&lt;br /&gt;                 (if (zero? (aget a i))&lt;br /&gt;                   (conj result i)&lt;br /&gt;                   result)))))))&lt;br /&gt;&lt;/pre&gt;and of course &lt;a href="http://github.com/richhickey/clojure-contrib/blob/dd497fb5154f8a26f9a09af7361981cb196bdf67/src/clojure/contrib/lazy_seqs.clj"&gt;the one from contrib&lt;/a&gt;: &lt;br /&gt;&lt;pre name="code" class="brush:clj"&gt;(defvar primes&lt;br /&gt;  (concat &lt;br /&gt;   [2 3 5 7]&lt;br /&gt;   (lazy-seq&lt;br /&gt;    (let [primes-from&lt;br /&gt;   (fn primes-from [n [f &amp; r]]&lt;br /&gt;     (if (some #(zero? (rem n %))&lt;br /&gt;        (take-while #(&amp;lt;= (* % %) n) primes))&lt;br /&gt;       (recur (+ n f) r)&lt;br /&gt;       (lazy-seq (cons n (primes-from (+ n f) r)))))&lt;br /&gt;   wheel (cycle [2 4 2 4 6 2 6 4 2 4 6 6 2 6  4  2&lt;br /&gt;   6 4 6 8 4 2 4 2 4 8 6 4 6 2  4  6&lt;br /&gt;   2 6 6 4 2 4 6 2 6 4 2 4 2 10 2 10])]&lt;br /&gt;      (primes-from 11 wheel))))&lt;br /&gt;  "Lazy sequence of all the prime numbers.")&lt;br /&gt;&lt;/pre&gt;Instead I came up with my own bad one...&lt;br /&gt;&lt;pre name="code" class="brush:clj"&gt;(defn primes [max-num](&lt;br /&gt;  loop [numbers (range 2 max-num) primes [] p 2]&lt;br /&gt;    (if (= (count numbers) 1)&lt;br /&gt;      (conj primes (first numbers))&lt;br /&gt;      (recur (filter #(not= (mod % p) 0) numbers) (conj primes p) (first (rest numbers))))))&lt;br /&gt;&lt;/pre&gt;Why is this so bad? Well it is horribly inefficient. It creates a list of integers up to the max-num that is the only input to the function. It then loops, each time removing all multiples of each prime -- just like a sieve is supposed to. However, most sieves take a prime p and remove 2p, 3p, 4p, etc. (often optimized to 3p, 5p, 7p, since all the even numbers are removed at the beginning.) This does the same thing, but it uses a filter to do it. So it goes through each member of the list to check if it is divisible by p. So it does way too many calculations. Next, it is constantly generating a new list of numbers to pass back into the loop. Maybe Clojure does some cleverness to make this not as memory inefficient as it sounds, but I don't think so. &lt;br /&gt;So what is it that I did not like about the other many examples out there or suggested by the community? Most of them used a lazy sequence. That's great and very efficient. However, it's not a concept that is easy to implement in other, less functional languages (Go Clojure!) On the other hand, the Rich Hickey example is much closer to what I wanted to do. However, it uses Java arrays. There is no duplication of the list and the non-primes are eliminated efficiently. Using Java arrays just seems non-idiomatic to say the least. The other examples did for JavaOne all used variable length lists instead of arrays.&lt;br /&gt;Anyways, I am satisfied to at least have a seemingly equivalent, idiomatic Clojure implementation. I looked at optimizing it through using type hints. I actually had to use a lot  of type hints (4) to get a 10% decrease in speed. Anyways, not that this is out here, others will improve it, as that shouldn't be too hard to do!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-7573175256535273851?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/7573175256535273851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=7573175256535273851' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/7573175256535273851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/7573175256535273851'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/11/clojures-primes-shootout.html' title='Clojures Primes Shootout'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-1345243523016672431</id><published>2009-11-03T21:34:00.000-08:00</published><updated>2009-11-03T21:34:23.439-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Persistent Data Structures</title><content type='html'>A few weeks ago I blogged about &lt;a href="http://fupeg.blogspot.com/2009/10/concurrency-patterns-java-scala-and.html"&gt;concurrency patterns and their relative tradeoffs&lt;/a&gt;. There were some really poor comments from Clojure fans -- the kind of abusive language and trolling that reminded me of Slashdot in its heyday. In fact, for the first time in a very long time, I had to actually delete comments... A lot of people get confused by the fact that I used Clojure as a representative for software transactional memory, and thought that I was talking about concurrency in Clojure. Anyways, I was flattered that Stuart Halloway commented on my blog. He said I needed to watch &lt;a href="http://www.blogger.com/"&gt;&lt;span id="goog_1257210959999"&gt;&lt;/span&gt;Rich Hickey's talk on persistent data structures&lt;span id="goog_1257210960000"&gt;&lt;/span&gt;&lt;/a&gt;. So I did. I wanted to embed it on my blog, but it didn't look like InfoQ supports that. So I stole his slides instead:&lt;br /&gt;&lt;div id="__ss_2407465" style="text-align: left; width: 425px;"&gt;&lt;a href="http://www.slideshare.net/michael.galpin/persistent-data-structures-and-managed-references" style="display: block; font: 14px Helvetica,Arial,Sans-serif; margin: 12px 0 3px 0; text-decoration: underline;" title="Persistent Data Structures And Managed References"&gt;Persistent Data Structures And Managed References&lt;/a&gt;&lt;object height="355" style="margin: 0px;" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=richhickeypersistentdatastructuresandmanagedreferences-091102191105-phpapp02&amp;stripped_title=persistent-data-structures-and-managed-references" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=richhickeypersistentdatastructuresandmanagedreferences-091102191105-phpapp02&amp;stripped_title=persistent-data-structures-and-managed-references" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="font-family: tahoma,arial; font-size: 11px; height: 26px; padding-top: 2px;"&gt;View more &lt;a href="http://www.slideshare.net/" style="text-decoration: underline;"&gt;documents&lt;/a&gt; from &lt;a href="http://www.slideshare.net/michael.galpin" style="text-decoration: underline;"&gt;michael.galpin&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;A little after all of this, I learned that persistent data structures were coming to Scala. So a lot of folks seem to think that these are pretty important. So why is that exactly? It was time to do some homework...&lt;br /&gt;&lt;br /&gt;You can read some &lt;a href="http://en.wikipedia.org/wiki/Persistent_data_structure"&gt;basic info on Wikipedia&lt;/a&gt;. You can go to the original source, &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.20.4164"&gt;Phil Bagwell's paper&lt;/a&gt;. The latter is very important. What's amazing is that these are relatively new ideas, i.e. the science behind this is less than ten years old. Anyways, I would say that the important thing about persistent data structures is that they are data structures designed for versioning. You never delete or for that matter change anything in place, you simply create new versions. Thus it is always possible to "rollback" to a previous version. Now you can see how this is a key ingredient for software transactional memory.&lt;br /&gt;&lt;br /&gt;Going back to the original ideas... Bagwell's VLists are the foundation for persistent arrays and thus persistent hashtables in Clojure. These form the foundation of Clojure's Multi-Version Concurrency Control, which in turn is the basis of its STM.&lt;br /&gt;&lt;br /&gt;These are not just persistent data structures, they are a very efficient implementation of the persistent data structure concept. Each incremental version of a list shares common data with the previous version. Of course you still pay a price for getting the built-in versioning, but this is minimized to some degree.&lt;br /&gt;&lt;br /&gt;Scala fans should also be interested in persistent data structures. They are coming to Scala, which is supposed to be available in beta by the end of this month. The aforementioned Bagwell did his work at EPFL -- the same EPFL that is the epicenter of Scala. Indeed, Bagwell himself has contributed to improving the implementations of VLists in Scala. With VLists in tow, Scala STM is just around the corner.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-1345243523016672431?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/1345243523016672431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=1345243523016672431' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/1345243523016672431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/1345243523016672431'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/11/persistent-data-structures.html' title='Persistent Data Structures'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-6165567619446999109</id><published>2009-10-27T16:00:00.000-07:00</published><updated>2009-10-27T16:00:33.900-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Minimalism? Programming? Huh?</title><content type='html'>Last week, I was at the Strange Loop conference, and it was a great conference. It &lt;a href="http://fupeg.blogspot.com/2009/10/concurrency-patterns-java-scala-and.html"&gt;inspired one blog post &lt;/a&gt;that managed to piss some Clojure people off. So here is another. This time I'm going after the closing keynote, Alex Payne. Here are his slides, including detailed notes.&lt;br /&gt;&lt;div id="__ss_2338110" style="text-align: left; width: 425px;"&gt;&lt;a href="http://www.slideshare.net/al3x/strange-loop-2009-keynote-minimalism-in-computing" style="display: block; font: 14px Helvetica,Arial,Sans-serif; margin: 12px 0 3px 0; text-decoration: underline;" title="Strange Loop 2009 Keynote: Minimalism in Computing"&gt;Strange Loop 2009 Keynote: Minimalism in Computing&lt;/a&gt;&lt;object height="355" style="margin: 0px;" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=strangeloop2009-091024174029-phpapp02&amp;stripped_title=strange-loop-2009-keynote-minimalism-in-computing" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=strangeloop2009-091024174029-phpapp02&amp;stripped_title=strange-loop-2009-keynote-minimalism-in-computing" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="font-family: tahoma,arial; font-size: 11px; height: 26px; padding-top: 2px;"&gt;View more &lt;a href="http://www.slideshare.net/" style="text-decoration: underline;"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/al3x" style="text-decoration: underline;"&gt;Alex Payne&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;So where to begin... Even though I am going to harsh on this, I will give it very high marks. Why? Because it was thought provoking. If something makes you think long and hard about how and why you do your job, that is a good thing. I worry about people who do not question their assumptions on a regular basis.&lt;br /&gt;Ok, so now on to what you've been waiting for -- the harshness. I hate software engineering analogies. Well, not all, but most. I hate when people try to romanticize about what they do by making a far-fetched analogy to something more glamorous. If you're a programmer, you're not a rock star. You're not an artist. You're not a musician. You're not even a scientist. Sorry. Despite having the word "architect" in my official job title, I would add that you're not an architect either.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_XmwdENwf53s/Sudxt52NKkI/AAAAAAAAAso/g4KIIxraz34/s1600-h/mugshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_XmwdENwf53s/Sudxt52NKkI/AAAAAAAAAso/g4KIIxraz34/s400/mugshot.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;You're a programmer. At best, you're an engineer, and that is really stretching it at times.&amp;nbsp;So obviously if I find it ridiculous to compare programming to things like creating art or making music, it seems even more ridiculous to compare the output of programming to art or music.&lt;br /&gt;&lt;br /&gt;That being said, I enjoy programming. It is not just a job. I also take pride in my work. I like to show off my code as much as the next guy.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_XmwdENwf53s/SudzEPqtqrI/AAAAAAAAAsw/Q_EtXQsIjUk/s1600-h/flasher2.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_XmwdENwf53s/SudzEPqtqrI/AAAAAAAAAsw/Q_EtXQsIjUk/s400/flasher2.gif" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;From this perspective, I can definitely appreciate Alex's thoughts on minimalism. Or perhaps more generally, associating some subjective qualities with programming. If an analogy to art or construction or whatever helps one express those subjective qualities, then fine. Just don't forget who you are, and maybe even try to find some pride in just that.&lt;br /&gt;&lt;br /&gt;Now I should really end this post now, on kind of a feel good note. But I won't. Instead, I want to touch on some of the *ahem* deeper thoughts that Alex's talk provoked. I was reminded of a paper I read several years ago that tried to explain two obviously overly general (and probably not politically correct) things: why Americans are good at software but not cars, while the Japanese are good at cars, but not software. I tried to find a link to this paper, and was quite sure that I had saved it in Delicious. However I could not find, and I'm convinced that Delicious lost it. Maybe it &lt;a href="http://fupeg.blogspot.com/2009/10/social-technology-fail.html"&gt;fell out of cache&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;Anyways, the crux of the argument is that Americans are good at getting something done quickly, even though the quality may be poor. So we are good innovators, but terrible craftsmen. This is a good fit for software, but obviously not cars.&lt;br /&gt;&lt;br /&gt;If you accept this idea, and it has its merits, then in a world of low quality, rapidly written code, is there any room for subjective qualities? Why should you take any pride in your work at all if its value is directly proportional to how quickly you can produce it, throw it away, and move on to something else? To some degree, doesn't the software world's affection with agile development codify these almost nihilistic ideals? Perhaps the propensity to try and compare programming to art is simply an act of desperation caused by the realization that you'd be better off &lt;a href="http://www.joelonsoftware.com/items/2009/09/23.html"&gt;giving up on good design and instead you should invest in duct-tape&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Anyways, this is a close-to-home topic for me. My day job often involves telling developers the "right" way to do something, and the more unsavory flip-side of this, telling developers when they've done things the "wrong" way. You don't make a lot of friends, but I'm an &lt;a href="http://www.typelogic.com/intj.html"&gt;INTJ&lt;/a&gt; so it works for me. Every once in awhile, I work with a programmer who writes beautiful code. Yeah, I said it. Any such programmer knows that they write good code, even if they don't like to talk about it. When you write good code, you constantly see bad code around you, and you can't help but get a big ego. I always compliment the good code, and it always surprises the arrogant pricks. They think I'm blown away and have never seen such good code. In reality, I just feel sorry for them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-6165567619446999109?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/6165567619446999109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=6165567619446999109' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/6165567619446999109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/6165567619446999109'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/minimalism-programming-huh.html' title='Minimalism? Programming? Huh?'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_XmwdENwf53s/Sudxt52NKkI/AAAAAAAAAso/g4KIIxraz34/s72-c/mugshot.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-3163911382077943291</id><published>2009-10-25T09:56:00.000-07:00</published><updated>2009-10-25T09:56:08.206-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='facebook'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='scalability'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><title type='text'>Social Technology Fail</title><content type='html'>This is the kind of posting that needs a disclaimer. I'm going to talk a little about recent changes at Facebook and Twitter, but strictly from a technology perspective. It goes without saying that I have no idea what I'm talking about. I am fortunate enough to be acquaintances with several engineers at both companies, and I have a college classmate (and fellow Pageboy) who seems to be a pretty important dude at Facebook, but I have no extra knowledge of these companies' technology than anybody else. So just to repeat: I have no idea what I'm talking about. You should really stop reading.&lt;br /&gt;&lt;br /&gt;Since you are still reading, then I will assume that you too enjoy being an armchair architect. Since my day job is as an architect at eBay, I tell myself that exercises such as this make me better at my job. Heh heh. Let's start with Facebook.&lt;br /&gt;&lt;br /&gt;For several months now, I've noticed an interesting&amp;nbsp;phenomenon at Facebook. My news feed would often have big gaps in it. I have about 200 friends on Facebook, and I'd say that around 70% of these friends are active, and probably 20-25% are very active Facebook users. So at any time I could look at my feed, and there would be dozens of posts per hour. However, if I scrolled back around 3-4 hours, I would usually find a gap of say 4-6 hours of no posts. The first time I ever noticed this, it was in the morning. So I thought that this gap must have been normal -- people were asleep. Indeed, most of my friends are in the United States. However, I started noticing this more and more often, and not always in the morning. It could be the middle of the day or late at night, and I would still see the same thing: big gaps. So what was going on?&lt;br /&gt;&lt;br /&gt;Well here's where the "I don't know what I'm talking about" becomes important. Facebook has been very happy to talk about their architecture, so that has given me speculation ammo. It is well known that Facebook has probably the biggest memcached installation in the world, with many terabytes of RAM dedicated to caching. Facebook has written about how they have even used memcached as a way to synchronize databases. It sure sounds a lot like memcached has evolved into something of a write-through cache. When you post something to Facebook, the web application that you interact with only sends your post to the cache.&lt;br /&gt;&lt;br /&gt;Now obviously reads are coming from cache, that's usually the primary use case for memcached. Now I don't know if the web app can read from either memcached and a data store (either a MySQL DB, or maybe Cassandra?) or if Facebook has gone for transparency here too, and augmented memcached to have read-through cache semantics as well. Here's where I am going to speculate wildly. If you sent all your writes to a cache, would you ever try to read from anything other than the cache? I mean, it would be nice to only be aware of the cache -- both from a code complexity perspective and from a performance perspective as well. It sure seems like this is the route that Facebook has taken. The problem is that not all of your data can fit in cache, even when your cache is multiple terabytes in size. Even if your cache was highly normalized data (which would be an interesting setup, to say the least) a huge site like Facebook is not going to squeeze all of their data into RAM. So if your "system of record" is something that cannot fit all of your data... inevitably some data will be effectively "lost." News feed gaps anyone?&lt;br /&gt;&lt;br /&gt;Maybe this would just be another useless musing -- an oddity that I noticed that maybe few other people would notice, along with a&amp;nbsp;harebrained explanation. However, just this week Facebook got a lot of attention for their latest "redesign" of their home application. Now we have the News Feed vs. the Live Feed. The News Feed is supposed to be the most relevant posts, i.e. incomplete by design. Now again, if your app can only access cache, and you can't store all of your data in cache, what do you do? Try to put the most "relevant" data in cache, i.e. pick the best data to keep in there. Hence the new News Feed. The fact that a lot of users have complained about this isn't that big of a deal. When you have a very popular application, any changes you make are going to upset a lot of people. However, you have to wonder if this time they are making a change not because they think it improves their product and will benefit users overall, but if instead it is a consequence of technology decisions. Insert cart before horse reference here...&lt;br /&gt;&lt;br /&gt;Facebook has a great (and well deserved) reputation in the technology world. I'm probably nuts for calling them out. A much easier target for criticism is Twitter. I was lucky enough to be part of their beta for lists. Now lists are a great idea, in my opinion. Lots of people have written about this. However, the implementation has been lacking to say the least. Here is a very typical attempt to use this feature, as seen through the eyes of Firebug:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_XmwdENwf53s/SuR7yDmQXtI/AAAAAAAAAsI/XyfRv4L9_5Y/s1600-h/Screen+shot+2009-10-25+at+9.23.44+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_XmwdENwf53s/SuR7yDmQXtI/AAAAAAAAAsI/XyfRv4L9_5Y/s400/Screen+shot+2009-10-25+at+9.23.44+AM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;It took my five attempts to add a user to a list. Like I said, this has been very typical in my experience. I've probably added 100+ users to lists, so I've got the data points to back up my statement. What the hell is going on? Let's look at one of these errors:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_XmwdENwf53s/SuR8ZWlgaAI/AAAAAAAAAsQ/LUMjH4EJoMc/s1600-h/Screen+shot+2009-10-25+at+9.26.41+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_XmwdENwf53s/SuR8ZWlgaAI/AAAAAAAAAsQ/LUMjH4EJoMc/s400/Screen+shot+2009-10-25+at+9.26.41+AM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Ah, a 503 Service Unavailable response... So it's a temporary problem. In fact look at the response body:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_XmwdENwf53s/SuR8-_EIr3I/AAAAAAAAAsY/pQG6yI-ijsI/s1600-h/Screen+shot+2009-10-25+at+9.29.18+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_XmwdENwf53s/SuR8-_EIr3I/AAAAAAAAAsY/pQG6yI-ijsI/s400/Screen+shot+2009-10-25+at+9.29.18+AM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;I love the HTML tab in Firebug... So this is the classic fail whale response. However, I'm only getting this on list requests. Well, at the very least I'm only consistently getting this on list requests. If the main Twitter site was giving users the fail whale at an 80% clip... In this case, I can't say exactly what is going. I could try to make something up (experiments with non-relational database?)&lt;br /&gt;However, this is much more disturbing to me than what's going on at Facebook. I don't get how you can release a feature, even in beta, that is this buggy. Since its release, &lt;a href="http://status.twitter.com/post/219264090/elevated-error-rate-being-worked-on"&gt;Twitter has reported a jump in errors&lt;/a&gt;. I will speculate and say that this is related to lists. It would not be surprising for a feature having this many errors to spill over and affect other features. If your app server is taking 6-10 seconds to send back (error) responses, then your app server is going to be able to handle a lot less requests overall. So not only is this feature buggy, but maybe it is making the whole site buggier.&lt;br /&gt;Now, I know what we (eBay) would do if this was happening: We'd wire-off the feature, i.e. disable it until we had fixed what was going wrong. Twitter on the other hand...&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_XmwdENwf53s/SuSBnEem2_I/AAAAAAAAAsg/B2P0ysJbecU/s1600-h/Screen+shot+2009-10-25+at+9.48.51+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_XmwdENwf53s/SuSBnEem2_I/AAAAAAAAAsg/B2P0ysJbecU/s400/Screen+shot+2009-10-25+at+9.48.51+AM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Huh? You've got a very buggy feature, so you're going to roll it out to more users? This just boggles my mind. I cannot come up with a rationale for something like this. I guess we can assume that Twitter has the problem figured out -- they just haven't been able to release the fix for whatever reason. Even if that was the case, shouldn't you roll out the fix and make sure that it works and nothing else pops up before increasing usage? Like I said, I just can't figure this one out...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-3163911382077943291?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/3163911382077943291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=3163911382077943291' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3163911382077943291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3163911382077943291'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/social-technology-fail.html' title='Social Technology Fail'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XmwdENwf53s/SuR7yDmQXtI/AAAAAAAAAsI/XyfRv4L9_5Y/s72-c/Screen+shot+2009-10-25+at+9.23.44+AM.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-5620164581449021156</id><published>2009-10-22T17:22:00.000-07:00</published><updated>2009-10-22T17:22:14.721-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Concurrency Patterns: Java, Scala, and Clojure</title><content type='html'>Today I was at The Strange Loop conference. The first talk I attended was by Dean Wampler on functional programming in Ruby. Dean brought up the Actor concurrency model and how it could be done in Ruby. Of course I am quite familiar with this model in Scala, though it is copied from Erlang (which copied it from some other source I'm sure.) The next talk I went to was on software transactional memory and how it is implemented in Clojure. I had read about Clojure's STM in Stuart Halloway's book, but I must admit that it didn't completely sink in at the time. I only understood the basic idea (it's like a database transaction, but with retries instead of rollbacks!) and the syntax. As I've become more comfortable with Clojure in general, the idea has made more and more sense to me.&lt;br /&gt;&lt;br /&gt;Now of course, no one size fits all. There are advantages and drawbacks to any concurrency model. A picture of these pros and cons kind of formed in my head today during the STM talk. I turned them into pictures. Here is the first one:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_XmwdENwf53s/SuDrz0f3vpI/AAAAAAAAAro/FGzwdmvBCBo/s1600-h/Screen+shot+2009-10-22+at+6.25.40+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_XmwdENwf53s/SuDrz0f3vpI/AAAAAAAAAro/FGzwdmvBCBo/s400/Screen+shot+2009-10-22+at+6.25.40+PM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;This is meant to be a measure of how easy it is to write correct concurrent code in Java, Scala, and Clojure. It is also meant to measure how easy it is to undersand somebody else's code. I think these two things are highly correlated. I chose to use these various languages, though obviously this is somewhat unfair. It wold be more accurate to say "locking/semaphores" instead of Java, the Actor model of Scala, and software transactional memory instead of Clojure -- but you get the point. So what does this graph mean?&lt;br /&gt;Well obviously, I think Java is the most difficult language to write correct code. What may be surprising to some people is that I think Clojure is only a little simpler. To write correct code in Clojure, you have to figure out what things need to be protected by a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;dosync&lt;/b&gt;&lt;/span&gt; macro, and make sure those things are declared as &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;ref&lt;/b&gt;&lt;/span&gt;s. I think that would be an easy thing to screw up. It's still easier than Java, where you have to basically figure out the same things, but you must also worry about multiple lock objects, lock sequencing, etc. In Clojure you have to figure out what has to be protected, but you don't have to figure out how to protect it -- the language features take care of that.&lt;br /&gt;So Clojure and Java are similar in difficulty, but what about Scala and the Actor model? I think this is much easier to understand. There are no locks/transactions. The only hard part is making sure that you don't send the same mutable object to different actors. This is somewhat similar to figuring what to protect in Clojure, but it's simpler. You usually use immutable case classes for the messages sent between actors, but these are used all over the place in Scala. It's not some special language feature that is only used for concurrency. Ok, enough about easy to write/understand code, there are other important factors, such as efficiency:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_XmwdENwf53s/SuDvm_81GSI/AAAAAAAAArw/ffTWyAqpvGA/s1600-h/Screen+shot+2009-10-22+at+6.26.35+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_XmwdENwf53s/SuDvm_81GSI/AAAAAAAAArw/ffTWyAqpvGA/s400/Screen+shot+2009-10-22+at+6.26.35+PM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Perhaps this should really be described as memory efficiency. In this case Java and the locking model is the most efficient. There is only copy of anything in such a system, as that master copy is always appropriately protected by locks. Scala, on the other hand, is far less efficient. If you send around messages between actors, they need to be immutable, which means a lot of copies of data. Clojure does some clever things around copies of data, making it more efficient than Scala. Some of this is lost by the overhead of STM, but it still has a definite advantage over Scala. Like in many systems, there is a tradeoff between memory and speed:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_XmwdENwf53s/SuDxH4aKQHI/AAAAAAAAAr4/i0X7WsuW8Mk/s1600-h/Screen+shot+2009-10-22+at+6.55.54+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_XmwdENwf53s/SuDxH4aKQHI/AAAAAAAAAr4/i0X7WsuW8Mk/s400/Screen+shot+2009-10-22+at+6.55.54+PM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Scala is the clear king of speed. Actors are more lightweight than threads, and a shared nothing approach means no locking, so concurrency can be maximized. The Java vs. Clojure speed is not as clear. Under high write contention, Clojure is definitely slower than Java. The more concurrency there is, the more retries that are going on. However, there is no locking and this really makes a big deal if there are a lot more reads than writes, which is a common characteristic of concurrent systems. So I could definitely imagine scenarios where the higher concurrency of Clojure makes it faster than Java. Finally, let's look at reusability.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_XmwdENwf53s/SuDyzp59cII/AAAAAAAAAsA/OnTm8kcXc9g/s1600-h/Screen+shot+2009-10-22+at+6.26.53+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_XmwdENwf53s/SuDyzp59cII/AAAAAAAAAsA/OnTm8kcXc9g/s400/Screen+shot+2009-10-22+at+6.26.53+PM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;By reusability, I mean is how reusable (composable) is a piece of concurrent code that you write with each of these languages/paradigms? In the case of Java, it is almost never reusable unless it is completely encapsulated. In other words, if your component/system has any state that it will share with another component, then it will not be reusable. You will have to manually reorder locks, extend synchronization blocks, etc. Clojure is the clear winner in this arena. The absence of locks and automatic optimistic locking really shine here. Scala is a mixed bag. On one hand, the Actor model is very reusable. Any new component can just send the Actor a message. Of course you don't know if it will respond to the message or not, and that is a problem. The bigger problem is the lack of atomicity. If one Actor needs to send messages to two other Actors, there are no easy ways to guarantee correctness.&lt;br /&gt;Back in June, I heard Martin Odersky says that he wants to add STM to Scala. I really think that this will be interesting. While I don't think STM is always the right solution, I think the bigger obstacle for adoption (on the Java platform) is the Clojure language itself. It's a big leap to ask people to give up on objects, and that is exactly what Clojure requires you to do. I think a Scala STM could be very attractive...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-5620164581449021156?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/5620164581449021156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=5620164581449021156' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/5620164581449021156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/5620164581449021156'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/concurrency-patterns-java-scala-and.html' title='Concurrency Patterns: Java, Scala, and Clojure'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_XmwdENwf53s/SuDrz0f3vpI/AAAAAAAAAro/FGzwdmvBCBo/s72-c/Screen+shot+2009-10-22+at+6.25.40+PM.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-7608431210974785657</id><published>2009-10-20T13:02:00.000-07:00</published><updated>2009-10-20T13:02:30.878-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='ie8'/><category scheme='http://www.blogger.com/atom/ns#' term='safari'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='chrome'/><category scheme='http://www.blogger.com/atom/ns#' term='opera'/><title type='text'>Don't Dream It's Over</title><content type='html'>&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/9B7H_f4q2kg&amp;hl=en&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/9B7H_f4q2kg&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Sometimes you need some 80's music. While you listen to that song, I want you to think about something: the Opera browser. As an OG geek, I used to use Opera -- I even paid for it. It was so much better than IE and that was back in the day when there was just the Mozilla Suite Monster, no Firefox. Sure, there were sites that didn't work well in it, or that actively discriminated against it (including my current employer...) That was ok. It was so much faster than anything else out there, that it didn't matter.&lt;br /&gt;&lt;br /&gt;As the world has turned over the years, history has proved Opera right. How fast your browser is does matter. How secure your browser is does matter. There is plenty of room for innovation in the browser space: tabs, download managers, speed dial, magic wand, etc. So many of Opera's ideas have been taken by the Firefoxes, Safaris, and most lately, the Chromes of the world, and touted as innovations -- that were then copied by IE. Meanwhile, what's happened to Opera? It doesn't always pay to be right.&lt;br /&gt;&lt;br /&gt;I got news for you, Opera is still kicking butt. There has been a renewed focus on browser technology, and in particular what is collectively known as HTML 5. Apple, Google, Mozilla, and even Microsoft all like to talk about how awesomely they implement the HTML 5 specifications. Turns out they are still way behind Opera. Don't believe me? Take a look at @ppk's &lt;a href="http://quirksmode.org/dom/html5.html"&gt;HTML 5 browser comparison&lt;/a&gt;. Or perhaps you are more visual...&lt;br /&gt;&lt;br /&gt;Code (courtesy of a colleague):&lt;br /&gt;&lt;pre name="code" class="brush:html"&gt;&amp;lt;form&gt; &lt;br /&gt;    &amp;lt;datalist id="mylist"&gt; &lt;br /&gt;        &amp;lt;option label="Mr" value="Mr"&gt; &lt;br /&gt;        &amp;lt;option label="Ms" value="Ms"&gt; &lt;br /&gt;        &amp;lt;option label="Professor"value="Prof"&gt; &lt;br /&gt;    &amp;lt;/datalist&gt; &lt;br /&gt;    &amp;lt;div class="entry"&gt; &lt;br /&gt;        &amp;lt;label for="form-1"&gt;Name (required) &amp;lt;/label&gt; &lt;br /&gt;        &amp;lt;input id="form-1" name="name" type="text" autofocus required&gt; &lt;br /&gt;        &amp;larr; autofocus here &amp;lt;/div&gt; &lt;br /&gt;    &amp;lt;div class="entry"&gt; &lt;br /&gt;        &amp;lt;label for="form-2"&gt;Title&amp;lt;/label&gt; &lt;br /&gt;        &amp;lt;input id="form-2" name="title" list="mylist" type="text"&gt; &lt;br /&gt;    &amp;lt;/div&gt; &lt;br /&gt;    &amp;lt;div class="entry"&gt; &lt;br /&gt;        &amp;lt;label for="form-4"&gt;Age&amp;lt;/label&gt; &lt;br /&gt;        &amp;lt;input id="form-4" name="age" type="number" min="18" max="25"&gt; &lt;br /&gt;    &amp;lt;/div&gt; &lt;br /&gt;    &amp;lt;div class="entry"&gt; &lt;br /&gt;        &amp;lt;label for="form-5"&gt;Email (required)&amp;lt;/label&gt; &lt;br /&gt;        &amp;lt;input id="form-5" name="email" type="email" required&gt; &lt;br /&gt;    &amp;lt;/div&gt; &lt;br /&gt;    &amp;lt;div class="entry"&gt; &lt;br /&gt;        &amp;lt;label for="form-6"&gt;Blogs&amp;lt;/label&gt; &lt;br /&gt;        &amp;lt;input id="form-6" name="url" type="url"&gt; &lt;br /&gt;    &amp;lt;/div&gt; &lt;br /&gt;    &amp;lt;div class="entry"&gt; &lt;br /&gt;        &amp;lt;label for="form-7"&gt;Date of Birth&amp;lt;/label&gt; &lt;br /&gt;        &amp;lt;input id="form-7" name="dob" type="date"&gt; &lt;br /&gt;    &amp;lt;/div&gt; &lt;br /&gt;    &amp;lt;div class="entry"&gt; &lt;br /&gt;        &amp;lt;label for="form-8"&gt;Attractiveness &amp;lt;/label&gt; &lt;br /&gt;        &amp;lt;input id="form-8" name="a" type="range" step="0.5" min="1" max="10" value="5"&gt; &lt;br /&gt;        &amp;lt;output name="result" onforminput="value=a.value"&gt;5&amp;lt;/output&gt; &lt;br /&gt;    &amp;lt;/div&gt; &lt;br /&gt;    &amp;lt;div class="button"&gt; &lt;br /&gt;        &amp;lt;button type=submit&gt;Submit&amp;lt;/button&gt; &lt;br /&gt;    &amp;lt;/div&gt; &lt;br /&gt;&amp;lt;/form&gt;&lt;br /&gt;&lt;/pre&gt;Opera:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_XmwdENwf53s/St4UpfXxlBI/AAAAAAAAArQ/2xEJ42YPZfo/s1600-h/Screen+shot+2009-10-20+at+12.49.48+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_XmwdENwf53s/St4UpfXxlBI/AAAAAAAAArQ/2xEJ42YPZfo/s400/Screen+shot+2009-10-20+at+12.49.48+PM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_XmwdENwf53s/St4Uzlwzi1I/AAAAAAAAArY/dp96bLDNcR4/s1600-h/Screen+shot+2009-10-20+at+12.49.58+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_XmwdENwf53s/St4Uzlwzi1I/AAAAAAAAArY/dp96bLDNcR4/s400/Screen+shot+2009-10-20+at+12.49.58+PM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Latest Chromium Nightly:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_XmwdENwf53s/St4U-JuPpoI/AAAAAAAAArg/UVxl6YjRmjA/s1600-h/Screen+shot+2009-10-20+at+12.50.30+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_XmwdENwf53s/St4U-JuPpoI/AAAAAAAAArg/UVxl6YjRmjA/s400/Screen+shot+2009-10-20+at+12.50.30+PM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;As you can see, Opera does a great job of implementing many of the new markups in HTML 5, while Chrome .... not so much. Big deal, right? You can do all of these things with JavaScript you say. Yeah, but not only will that be a lot of heavy JS, but it will lose semantics. Don't think that matters? Well, not only do those semantics matter to folks who use screen readers, but it also matters to the most important user of the Internet: googlebot.&lt;br /&gt;&lt;br /&gt;Anyways, the point is that once again Opera is leading the way, not the folks who talk the loudest about pushing browser technology.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;span style="font-size: x-small;"&gt;Note: This blog post created with Opera.&lt;/span&gt;&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-7608431210974785657?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/7608431210974785657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=7608431210974785657' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/7608431210974785657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/7608431210974785657'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/dont-dream-its-over.html' title='Don&apos;t Dream It&apos;s Over'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XmwdENwf53s/St4UpfXxlBI/AAAAAAAAArQ/2xEJ42YPZfo/s72-c/Screen+shot+2009-10-20+at+12.49.48+PM.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-8600432470308060388</id><published>2009-10-19T22:36:00.000-07:00</published><updated>2009-10-19T22:36:59.571-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>HTML 5 Features on Mobile Browsers</title><content type='html'>Earlier today I looked for some help from the smarty folks that I follow on Twitter:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_XmwdENwf53s/St1Gf5yx_sI/AAAAAAAAArI/K4fwY2SKMRk/s1600-h/Screen+shot+2009-10-19+at+10.10.58+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_XmwdENwf53s/St1Gf5yx_sI/AAAAAAAAArI/K4fwY2SKMRk/s400/Screen+shot+2009-10-19+at+10.10.58+PM.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;Both &lt;a href="http://twitter.com/sophistifunk"&gt;@sophistifunk&lt;/a&gt; and my colleague &lt;a href="http://twitter.com/rragan"&gt;@rragan&lt;/a&gt; responded that I should look at &lt;a href="http://twitter.com/ppk"&gt;@ppk&lt;/a&gt;'s &lt;a href="http://quirksmode.org/dom/html5.html"&gt;HTML 5 compatibility table&lt;/a&gt; and &lt;a href="http://www.quirksmode.org/webkit.html"&gt;WebKit comparison table&lt;/a&gt;. Now these are great resources, and I already had an appreciation for them. However, even put together, they do not, in my opinion, accurately describe the state of mobile web browser capabilities.&lt;br /&gt;&lt;br /&gt;Let me take a step back. First it should be said that I hate web standards. Seriously. As someone who has spent much of his adult life developing web applications, I understand why people like standards. Having to write code that is specific for each browser will drive you insane. I don't want to do that anymore than anyone else. However, standards are ex post facto so to speak. It is great to take things and create standards around them, but it is a losing battle to look to standards for innovation. If we had done that, there would be no such thing as Ajax -- or it could only be implemented using hidden IFrames...&lt;br /&gt;&lt;br /&gt;With that in mind, I have &lt;a href="http://fupeg.blogspot.com/2009/06/html-5-dont-believe-hype.html"&gt;never given much faith to HTML 5 as a standards lead revolution&lt;/a&gt;. This is one of the flaws in the compatibility/comparison tables. Let me give you a couple of examples. The WebKit comparison table shows that neither Android 1.0 or 1.5 supports geolocation (I know, I know, geolocation is a separate specification, but practically it is lumped in with HTML 5). Anybody with an Android phone knows that this is patently false. The Android browser defaults to Google's mobile home page, which uses the geolocation API to echo your location to you -- if you browser supports geolocation. So did @ppk just get this wrong? No, not really. The catch is that the Android browser is not just WebKit, it is also Gears, which implements the HTML 5 geolocation completely. So anybody using an Android phone (and there's going to be a lot of such folks very soon), has a geolocation-enabled browser. But you would not know this from reading the WebKit table.&lt;br /&gt;&lt;br /&gt;Another example is app cache. This is specification meant to enable offline applications. Again the WebKit table says that it is not supported in any Android browser. However, this functionality is once again implemented using Gears. In this case, I don't think it follows the specification exactly. Oh well.&lt;br /&gt;&lt;br /&gt;Oh, and one last nitpick... The HTML 5 comparison does not even mention database APIs. This is supported by the latest versions of the browsers in the iPhone and Android (and it has been for 1yr+ in both I think.) Yeah I know, @ppk can only run so many tests, and that will probably be listed in the future...&lt;br /&gt;&lt;br /&gt;I'm really not trying to diss @ppk and the data provided on quirksmode. It is tricky to assess mobile browser capabilities. That's why I was trying to be lazy in the first place and hope that somebody had done all of the hard work for me!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-8600432470308060388?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/8600432470308060388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=8600432470308060388' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/8600432470308060388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/8600432470308060388'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/html-5-features-on-mobile-browsers.html' title='HTML 5 Features on Mobile Browsers'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_XmwdENwf53s/St1Gf5yx_sI/AAAAAAAAArI/K4fwY2SKMRk/s72-c/Screen+shot+2009-10-19+at+10.10.58+PM.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-3233984538764411073</id><published>2009-10-18T15:47:00.000-07:00</published><updated>2009-10-18T15:47:59.067-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='intellij idea'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='netbeans'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>The IntelliJ IDEA Bomb</title><content type='html'>In case you missed &lt;a href="http://blogs.jetbrains.com/idea/2009/10/intellij-idea-open-sourced/"&gt;the announcement from JetBrains yesterday&lt;/a&gt;, the popular IntelliJ IDEA has gone free and open source. Sort of. There is now a community edition, that is &lt;a href="http://en.wikipedia.org/wiki/Free_and_open_source_software"&gt;FOSS&lt;/a&gt;, and an enterprise edition that you must pay for. Why is this a big deal? Read on.&lt;br /&gt;&lt;br /&gt;IntelliJ really revolutionized Java development. It wasn't the first IDE to allow for code completion, or even the first Java IDE to do this. However, it was definitely a pioneer in code refactoring. And this was huge. It took many of the code improvement ideas catalogued by Martin Fowler, and turned them into simple commands that any programmer could use. This also allowed for things like code navigation, where you could go from the usage of a class or a method to the implementation (or at least the declaration, if the usage only referred to the interface.) This was only the beginning. IntelliJ was a pioneer of bringing in the Java ecosystem. I remember how much easier IntelliJ made it to use Struts, for example.&lt;br /&gt;&lt;br /&gt;This reminds me of my own personal use of IntelliJ over the years. When I first started working in enterprise Java development, I was working for a startup that built EJB applications targeted for WebLogic and WebSphere. For WebSphere, we used &lt;a href="http://en.wikipedia.org/wiki/IBM_VisualAge"&gt;Visual Age&lt;/a&gt; for Java. For WebLogic, we just used Kawa (a bare bones editor.) I hated Visual Age with a passion. It scarred me badly. For years afterwards, I stuck to simple text editors.&lt;br /&gt;&lt;br /&gt;Several year later (2003), I joined a fresh startup, KeepMedia (later renamed to&amp;nbsp;&lt;a href="http://www.mywire.com/"&gt;MyWire&lt;/a&gt;). Prior to KeepMedia, I had a short stint with a .NET startup, Iteration Software (later renamed to Istante, and sold to Oracle.) There I used Visual Studio quite a bit, and appreciated the productivity gains it provided. So at KeepMedia, I took a look at various Java IDEs: JBuilder, JDeveloper, and IntelliJ. I was one of three programmers at KeepMedia, and one of my colleagues was really in love with Struts. He worked on the front of KeepMedia, but I worked mostly on our back end system that integrated magazine content from publishers. I didn't have to use Struts for that obviously, but I did&amp;nbsp;occasionally help with the front end (we had three programmers after all.) I hated Struts, but IntelliJ made it more tolerable. The only negative about it was that it was flaky on Linux, but pretty much everything was flaky on Linux back then.&lt;br /&gt;&lt;br /&gt;After I worked at KeepMedia, I worked at a consulting company, LavaStorm Engineering (2004). I had been using IntelliJ for a long time, and was convinced that everything else was crap. One of my colleagues introduced me to Eclipse. I was horrified. Most of Eclipse's codebase came from an all-Java rewrite of Visual Age (the version I had used was written in Smalltalk.) So even though it shared no code with the beast that I had hated, it shared a lot of the look-and-feel. For example, take a look at the outline view in Eclipse (any version, even the most recent.) This was completely taken from Visual Age. Even the icons are exactly the same. There was no way I was going to give up my IntelliJ for that thing...&lt;br /&gt;&lt;br /&gt;A couple of years later, I was at another startup, Sharefare (which later changed its name to Ludi Labs.) Being a startup, there was no standardization arounds tools. However, everyone used Eclipse. I had warmed up to Eclipse (though I still preferred IntelliJ), and I had started writing Eclipse related articles for IBM. So I went with Eclipse there, as there were advantages to everyone using the same IDE (being able to share .project/.classpath, plugins, etc.)&lt;br /&gt;&lt;br /&gt;After Ludi Labs went down in early 2007, I joined eBay. To say we're a major Eclipse shop, would be putting it mildly...&lt;br /&gt;&lt;div id="__ss_1213009" style="text-align: left; width: 425px;"&gt;&lt;a href="http://www.slideshare.net/michael.galpin/eclipse-ebay-2009-1213009" style="display: block; font: 14px Helvetica,Arial,Sans-serif; margin: 12px 0 3px 0; text-decoration: underline;" title="Eclipse @eBay 2009"&gt;Eclipse @eBay 2009&lt;/a&gt;&lt;object height="355" style="margin: 0px;" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=eclipseebay-090402055009-phpapp01&amp;stripped_title=eclipse-ebay-2009-1213009" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=eclipseebay-090402055009-phpapp01&amp;stripped_title=eclipse-ebay-2009-1213009" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="font-family: tahoma,arial; font-size: 11px; height: 26px; padding-top: 2px;"&gt;View more &lt;a href="http://www.slideshare.net/" style="text-decoration: underline;"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/michael.galpin" style="text-decoration: underline;"&gt;michael.galpin&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;We're not the only major Java shop that has invested heavily in Eclipse plugins. If you're doing GWT, App Engine, or Android development, then you're probably using Eclipse too. I know I am. I didn't really start using IntelliJ again, until the past year. The reason was simple: Scala. It is the best IDE for doing Scala development currently. Actually IntelliJ's Scala offering vs. the competition, is similar to anything else. It's not that it necessarily has a lot more features, but it has similar and most importantly, it is of higher quality. Here's a great visualization of this key difference:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://stuffthathappens.com/blog/wp-content/uploads/2009/10/matrix.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="256" src="http://stuffthathappens.com/blog/wp-content/uploads/2009/10/matrix.png" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;This is why the open sourcing of IntelliJ is important. It's not that we didn't already have great open source IDEs for Java. No, it's more about &lt;a href="http://beust.com/weblog/archives/000520.html"&gt;what does this mean for IntelliJ&lt;/a&gt;. Will the attention to detail go down hill? Will the stable plugin ecosystem be disrupted?&lt;br /&gt;&lt;br /&gt;Of course, for most current and would-be users of IntelliJ, the availability of a free IntelliJ is really not big news. The free version is really quite limited. You're not going to build web apps, or apps that connect to databases, use web services, etc. Not with the community version, unless in-the-wild plugins became available that enable this. IntelliJ has awesome support for all of these things, but those parts of IntelliJ remain behind a price wall.&lt;br /&gt;&lt;br /&gt;There is one notable exception here: Scala. Right now, IntelliJ has the best Scala support. It has more features and less bugs than NetBeans, and it is much more stable than Eclipse. Scala support is one of the features supported in the community edition. That means a lot of newbie Scala developers can just use IntelliJ. This is great news. I would not give NetBeans or Eclipse to Scala newbies, for the simple reason that both of them report syntax errors inconsistently. In other words, both are guilty of either not identifying an error, or identifying a false error (or both.) That's anathema for somebody learning a language. I'm able to put up with it, simply because I know just enough Scala to say "you're wrong IDE" at times. I've rarely seen this happen with IntelliJ.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-3233984538764411073?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/3233984538764411073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=3233984538764411073' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3233984538764411073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3233984538764411073'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/intellij-idea-bomb.html' title='The IntelliJ IDEA Bomb'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-6355685033159417521</id><published>2009-10-13T22:58:00.000-07:00</published><updated>2009-10-13T22:58:11.529-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Manifests FTW</title><content type='html'>I came across a piece of code written by a colleague. It was a flexible XML/JSON parser. It would turn an XML or JSON structure into a map. The keys were strings. The values were either strings, lists, or maps. The lists could be lists of strings, lists, or maps. The maps had strings as keys and value as (wait for it) strings, lists, or maps. We had run across a bug recently. Usually a particular web service returned data that looked something like:&lt;br /&gt;&lt;pre name="code" class="brush:js"&gt;{ "details" : { "a" : "x", "b" : "y" } }&lt;br /&gt;&lt;/pre&gt;So we had code that looked like : &lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;val response = // code that called the parser&lt;br /&gt;val foo = response("details").asInstanceOf[Map[String,String]]("a")&lt;br /&gt;&lt;/pre&gt;However, one day we got some bad data:&lt;br /&gt;&lt;pre name="code" class="brush:js"&gt;{ "details" : "" }&lt;br /&gt;&lt;/pre&gt;So of course the earlier code blew up. I wanted to have something like this:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;trait SafeMapTrait {&lt;br /&gt;    def getString(key:String):String&lt;br /&gt;    def getList(key:String):List[AnyRef]&lt;br /&gt;    def getMap(key:String):Map[String, AnyRef]&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Now this can be accomplished pretty easily:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;class EasySafeMap(val map:Map[String, AnyRef]){&lt;br /&gt;  def getString(key:String):String = {&lt;br /&gt;    if (map.contains(key)){&lt;br /&gt;      if (map(key).isInstanceOf[String]) map(key).asInstanceOf[String] else null&lt;br /&gt;    } else null&lt;br /&gt;  }&lt;br /&gt;  // etc.    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;There would be similar methods for lists and maps. I didn't like this, and thought I should be able to do better. Looking at the final solution, I'm not sure that I did. But I did learn some things about Scala Manifests... Before we get there, let's look at me first naive attempt to do better:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;class NotSoSafeMap(val map:Map[String,AnyRef]){&lt;br /&gt;&lt;br /&gt;  def getString(key:String):String = getType(key)&lt;br /&gt;  def getList(key:String):List[AnyRef] = getType(key)&lt;br /&gt;  def getMap(key:String):Map[String,AnyRef] = getType(key)&lt;br /&gt;&lt;br /&gt;  private def getType[T](key:String):T  = {&lt;br /&gt;    val value = map.getOrElse(key, null)&lt;br /&gt;    if (value != null &amp;&amp; value.isInstanceOf[T]) value.asInstanceOf[T] else null&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;That would have been, huh? I really wanted to use a parameterized method for the extraction, comparison, casting. The problem with this is that there is no way to know the type T. You could explicitly add the parameter, i.e. getType[String](key) but it doesn't help because of erasure. I tried this instead:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;class NotSoSafeMap(val map:Map[String,AnyRef]){&lt;br /&gt;&lt;br /&gt;  def getString(key:String):String = getType(key,null)&lt;br /&gt;  def getList(key:String):List[AnyRef] = getType(key,null)&lt;br /&gt;  def getMap(key:String):Map[String,AnyRef] = getType(key,null)&lt;br /&gt;&lt;br /&gt;  private def getType[T](key:String, default:T):T  = {&lt;br /&gt;    val value = map.getOrElse(key, default)&lt;br /&gt;    if (value.isInstanceOf[T]) value.asInstanceOf[T] else default&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I thought that this might be better because of the type information being given in the default value. This didn't work. Using the null default seemed dumb, but even adding defaults like the empty string, an empty list, etc. did not help. Erasure was once again kicking my ass. So it was time to learn about Manifests. &lt;br /&gt;I had heard Jorge Ortiz talk about manifests previously. He has also written &lt;a href="http://scala-blogs.org/2008/10/manifests-reified-types.html"&gt;an excellent blog post about them&lt;/a&gt;. He told me that these were still "experimental" (i.e. undocumented) in Scala 2.7.x, but were officially part of the upcoming 2.8 release. Sounded good to me. Here is the solution I came up with:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;class SafeMap(val map:Map[String,AnyRef]){&lt;br /&gt;  import scala.reflect.Manifest&lt;br /&gt;&lt;br /&gt;  def getString(key:String):String = getType[String](key) match {&lt;br /&gt;    case Some(s:String) =&gt; s&lt;br /&gt;    case _ =&gt; null&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def getMap(key:String):Map[String, AnyRef] = getType[Map[String,AnyRef]](key) match {&lt;br /&gt;    case Some(m:Map[String, AnyRef]) =&gt; m&lt;br /&gt;    case _ =&gt; null&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def getList(key:String):List[AnyRef] = getType[List[AnyRef]](key) match {&lt;br /&gt;    case Some(list:List[AnyRef]) =&gt; list&lt;br /&gt;    case _ =&gt; null&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private def getType[T](key:String)(implicit m:Manifest[T]):Option[T] = {&lt;br /&gt;    map.getOrElse(key, null) match {&lt;br /&gt;      case a:AnyRef =&gt; if (m &gt;:&gt;  Manifest.classType(a.getClass)) Some(a.asInstanceOf[T]) else None&lt;br /&gt;      case null =&gt; None&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Ok, a few things to note here. First the local import of scala.reflect.Manifest. Again it's not a documented class, but it's in there. Now my getType method. Notice that it uses the function_name (param:type) (param:type) syntax. Also notice the implicit Manifest parameter. The callers don't add this, the compiler adds it for you. Next notice that it returns an Option class. I wanted it to just return T. However, I could not have a case where it returned null if T was the declared return type of the method. So I went with Option. Finally, notice the Manifest magic. That's the m &gt;:&gt; Manifest.classType(a.getClass). The right hand side of the call uses a factory method in the Manifest singleton object, to create a Manifest for the (class of the) value coming back from the map. The &gt;:&gt; operator checks to see if the right hand side represents a subclass of the left hand side. This is important. For the getMap method, the manifest will represent the Map trait (actually a Java interface in this case.) The call to a.getClass gives you the runtime class of a. Of course this runtime class implements the Map trait, but you can't do equality comparison. Hence the &gt;:&gt; operator. One last thing, notice that the getString method uses the explicit getType[String]. You would think that the compiler could infer this since the left hand is explicitly declared as a String. It doesn't. When I tried it without the explicit type parameter, my manifest would always Manifest[Nothing].&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-6355685033159417521?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/6355685033159417521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=6355685033159417521' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/6355685033159417521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/6355685033159417521'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/scala-manifests-ftw.html' title='Scala Manifests FTW'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-3611153583351066148</id><published>2009-10-10T17:10:00.000-07:00</published><updated>2009-10-10T17:10:57.332-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='katrina'/><category scheme='http://www.blogger.com/atom/ns#' term='facebook'/><category scheme='http://www.blogger.com/atom/ns#' term='pop culture'/><category scheme='http://www.blogger.com/atom/ns#' term='barack obama'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><category scheme='http://www.blogger.com/atom/ns#' term='history'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='9/11'/><title type='text'>The End of The Aughties</title><content type='html'>There are 72 days left in the Aughties, y'know the current decade: 2000 - 2009. I was looking back at the decade, and what are its most important events. Here's my little list:&lt;br /&gt;&lt;br /&gt;9/11 -- This is obvious. September 11, 2001 is clearly one of the most pivotal days in the history of the United States. In the previous century, there are probably only a couple of comparable events: the bombing of Pearl Harbor, V-E day, the moon landing, the JFK assassination. For several generations of Americans, 9/11 will be the most historical day of their life.&lt;br /&gt;&lt;br /&gt;The Election of Barack Obama -- President Obama's election was historical in so many ways. Obviously it was historic that an African American was elected President. It also marked a transition to a new generation -- Obama is 15 years younger than Bush or Clinton (and let's not even mention McCain.) Obama is not only a Democrat, but is not from the more conservative, Southern Democrats of Clinton and Jimmy Carter.&lt;br /&gt;&lt;br /&gt;Social Media -- Here's where maybe my perspective is skewed by living in Silicon Valley. Social media is not a single event, in fact it is a progression of events. To me, it really started with blogging and YouTube, and then exploded with MySpace, Facebook, and Twitter. It is a fundamental change in the Internet. Every user is a creator of content, as well as a consumer. It is the great democratizing effect of the Internet, and it is only getting started. Even now we are starting to see how businesses, celebrities, etc. realize that not only can they use social media as a channel to customers and fans, but that it is a two-way channel.&lt;br /&gt;&lt;br /&gt;Hurricane Katrina -- What made Hurricane Katrina so pivotal is that opened the eyes of Americans. It made people realize that many of their fellow Americans live in awful conditions. The divide between socioeconomic classes in America were never so obvious as during Katrina. When &lt;a href="http://www.youtube.com/watch?v=zIUzLpO1kxI"&gt;Kanye West went on TV and said that George Bush didn't care about black people&lt;/a&gt;, he wasn't just being a &lt;a href="http://www.youtube.com/watch?v=IO_QIMNRreg"&gt;jackass&lt;/a&gt;, he was stating a sentiment shared by a lot of people.&lt;br /&gt;&lt;br /&gt;The iPhone -- What did I say earlier about having a Silicon Valley perspective? Anyways... The iPhone has completely changed so many things for so many people. In the 90's, The Internet changed people's lives by bringing them information. Now the iPhone lets them carry it around in their pocket. Other phones were certainly moving in that direction, but the iPhone broke through by combining a large display with highly usable touch based interface. This revolution continued with the release of the App Store. Now don't get me wrong. A lot of other phones are following suit -- but that's exactly why the iPhone was so historical.&lt;br /&gt;&lt;br /&gt;That's my short list. I know it's obviously biased from me being American and living in Silicon Valley. What did I miss? What doesn't belong?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-3611153583351066148?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/3611153583351066148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=3611153583351066148' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3611153583351066148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3611153583351066148'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/end-of-aughties.html' title='The End of The Aughties'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-3654862330890942960</id><published>2009-10-08T20:20:00.000-07:00</published><updated>2009-10-08T20:20:29.327-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mlb'/><category scheme='http://www.blogger.com/atom/ns#' term='san francisco giants'/><category scheme='http://www.blogger.com/atom/ns#' term='baseball'/><title type='text'>San Francisco Giants 2009</title><content type='html'>The Giants had a pretty good season. They were in contention for a playoff spot until the final couple of weeks. But they didn't make it. Folks around here are busy talking about what the Giants need to do to take the next step. The answer is obvious all at once: they need better hitting. However the problem is that the Giants don't actually know how to evaluate hitting talent. So they really don't have any chance at getting good hitting without paying a huge price for it. Let's take a look at some numbers to understand this.&lt;br /&gt;&lt;br /&gt;One easy way to evaluate the Giants is by looking at the players who have come up through their farm system. Of their homegrown players that had at least 200 plate appearances, on average they saw 3.62 pitches per plate appearance and walked in 7.2% of their plate appearances. To be fair, Fred Lewis has very good plate discipline (and his plate appearances went way down this year.) If you take him out, then the numbers are 3.52 pitches per plate appearance and a 6.8% walk rate. For comparison's sake, if you look at the top seven teams (in terms of runs scored), they average a walk in 9.8% of their plate appearances.&lt;br /&gt;&lt;br /&gt;So the Giants farm system sucks. Maybe they can sign good hitters? Nope. If you look at their top hitters that they signed from other teams, they see 3.58 pitches per plate appearance and a 5.9% walk rate. That's right, they see a few more pitches, but they walk even less. The Giants even made a "big" trade at midseason, for Freddy Sanchez. Everyone is concerned that Freddy might have become injury prone suddenly. What they should really be worrying about is that Freddy sucks. He sees 3.81 pitches per plate appearance, which is not too bad. However, he only walks 4.5% of the time. Further, his 0.417 career slugging percentage is just awful, even for a second baseman (which is generally a strong offensive position in modern baseball.) So he doesn't swing at everything (he also has a low strikeout rate) but yet he still does not try to get a good pitch to hit and winds up playing for a single. This is your blockbuster trade material? This is what you get in exchange for the second best pitcher in your farm system?&lt;br /&gt;&lt;br /&gt;Yeah, so clearly the Giants front office has no idea what makes a good hitter.&amp;nbsp;People like to say that the Giants home park is a great pitchers park, as it is a tough place to hit home runs. That does not make it a tough place to take a bad pitch or take a walk. In fact, you would think that in such a park, they would an even higher premium on hitters who can get on base any way they can. It's funny, you often hear that the reason that the A's are no longer a good offensive team is because other teams figured out what they were doing. If you look at the Yankees and Red Sox, or for that matter the Rays and the Rockies, you can see evidence of this. However, clearly there is one team that has not figured things out and that is the Giants.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-3654862330890942960?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/3654862330890942960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=3654862330890942960' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3654862330890942960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3654862330890942960'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/10/san-francisco-giants-2009.html' title='San Francisco Giants 2009'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-4864277159499702126</id><published>2009-09-15T17:16:00.000-07:00</published><updated>2009-09-15T17:16:23.316-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='algorithms'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala Word Clouds</title><content type='html'>Just before I went to bed last night, I got an &lt;a href="http://twitter.com/dcbriccetti/status/3997782106"&gt;interesting tweet from Dave Briccetti&lt;/a&gt;. You can see from the &lt;a href="http://gist.github.com/187107"&gt;link in tweet&lt;/a&gt;&amp;nbsp;what the problem was, and if you look at the bottom of the page, you can see the clever solution by Jorge Ortiz. Right after I read the tweet from Dave, I asked my wife how long until the end of the TV that she was watching. She said seven minutes. I decided that wasn't enough time, so I went to sleep.&lt;br /&gt;&lt;br /&gt;I didn't look at the problem again until today during lunch. By then, I saw Jorge's solution and I saw no way to improve on it. However, this inspired a little experiment for me. Actually it mostly reminded me of a programming problem that I was given a few years back by a well known company that will remain anonymous as they are very touchy about people talking about their interviewing process. The problem was essentially the same as Dave's problem -- take a bunch of sentences (instead of tweets), figure out the most frequent words. There was a twist though -- I was not allowed to use any Java collection. Actually I could not use anything outside of the java.lang package, so I was pretty much stuck with arrays...&lt;br /&gt;&lt;br /&gt;At the time, I figured that I would have to either implement my own hash table and a sort, but then I came up with a way to solve the problem with no hash table. So when I saw Dave's problem, I thought "wow my old solution will be so much more awesome in Scala":&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;def createCloud(strings:Seq[String])={&lt;br /&gt;  val x:List[String] = Nil&lt;br /&gt;  var s = ("",0)&lt;br /&gt;  val cloud = new scala.collection.mutable.ArrayBuffer[Tuple2[String,Int]]&lt;br /&gt;  strings.map(_.split("\\s").toList.sort(_ &amp;lt; _)).foldLeft(x){mergeSorted(_, _)}.foreach( (a) =&gt; {&lt;br /&gt;    if (a == s._1) &lt;br /&gt;      cloud(cloud.length - 1) = (a, s._2 + 1)&lt;br /&gt;    else&lt;br /&gt;      cloud += (a,1)&lt;br /&gt;    s = cloud(cloud.length - 1)&lt;br /&gt;  })&lt;br /&gt;  cloud.toList.sort((a,b) =&gt; a._2 &gt; b._2)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Ok, so I cheated this time and used an ArrayBuffer instead of array. In my solution years ago, I made an array whose size was the total number of words (worst case scenario.) I didn't have tuples, so I had to use two arrays. Anyways, the idea here is to split each sentence into a list of words, and then sort that list of words. Now merge together each sorted list, and keep things sorted using a &lt;a href="http://en.wikipedia.org/wiki/Merge_sort"&gt;merge sort&lt;/a&gt;. Of course you could turn everything into a big list first using flatMap, similar to Jorge's solution, and then sort. Anyways, you then roll up the sorted list, taking advantage of the fact that it is sorted. You never have to look up a word to see if it has been encountered before, because of the sorting. You just keep track of the last word encountered, and just compare the next word to the last word to determine if the word has been previously encountered and thus needs to be incremented. Of course you must be wondering about the aforementioned merge sort. Here is a Scala implementation of it:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;def mergeSorted[A](comparator: (A,A) =&gt; Boolean)(x:List[A], y:List[A]):List[A] = {&lt;br /&gt;  if (x.isEmpty) y&lt;br /&gt;  else if (y.isEmpty) x&lt;br /&gt;  else if (comparator(x.head, y.head)) x.head :: mergeSorted(comparator)(x.tail, y)&lt;br /&gt;  else y.head :: mergeSorted(comparator)(x, y.tail)&lt;br /&gt;}&lt;br /&gt;  &lt;br /&gt;def mergeSorted[A &lt;% Ordered[A]](x:List[A], y:List[A]):List[A] = mergeSorted((a:A,b:A) =&gt; a &amp;lt; b)(x,y)&lt;br /&gt;&lt;/pre&gt;While writing this, I decided that I should touch up my knowledge of currying and partially applied functions in Scala, so I read about &lt;a href="http://www.codecommit.com/blog/scala/function-currying-in-scala"&gt;this on Daniel Spiewak's blog&lt;/a&gt;. The first version of mergeSorted is very generic and takes a comparator. This is what lead me into the world of currying. Actually, my first version of the above looked like this:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;class MergeSorter[A](comparator: (A,A) =&gt; Boolean){&lt;br /&gt;  def apply(x:List[A], y:List[A]):List[A] = {&lt;br /&gt;    if (x.isEmpty) y&lt;br /&gt;    else if (y.isEmpty) x&lt;br /&gt;    else if (comparator(x.head, y.head)) x.head :: apply(x.tail, y)&lt;br /&gt;    else y.head :: apply(x, y.tail)    &lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I created a class to encapsulate the sort. In some ways I like this syntax a little better, but it made the second version of the sort a little uglier. I wanted a "default" sort that could be used for anything implementing Scala's &lt;a href="http://www.scala-lang.org/docu/files/api/scala/Ordered.html"&gt;Ordered&lt;/a&gt; trait. It is this second version that I used in the createCloud function above, as strings can be implicitly converted to &lt;a href="http://www.scala-lang.org/docu/files/api/scala/runtime/RichString.html"&gt;RichString&lt;/a&gt; which implements Ordered.&lt;br /&gt;&lt;br /&gt;It is still easy to use mergeSorted with objects that do not implement Ordered, or to provide a different sort function for those that do:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;// provide your own sort&lt;br /&gt;val sList = &lt;br /&gt;  mergeSorted((s1:String, s2:String) =&gt; s1.toLowerCase &amp;lt; s2.toLowerCase)(List("aa","aB","Cb"), List("Ab", "ca"))&lt;br /&gt;// create a reusable sort&lt;br /&gt;val listSort = mergeSorted( (a:List[Any], b:List[Any]) =&gt; a.length &amp;lt; b.length) _&lt;br /&gt;val z = listSort(List(List("a","b"), List(1,2,3)), List(List(true,true,true), List("x","y","z","w")))&lt;br /&gt;&lt;/pre&gt;In the first example, we create a new sort by providing different sorting function that is case insensitive. It is then applied to a list of strings. In the second example, we create the sorting function and assign to a val. Notice the mysterious underscore _ at the end of the statement. This creates a partially applied function. If you forget the underscore, the Scala compiler actually provides a pretty useful error message about this. With this, we can then apply the function however we want.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-4864277159499702126?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/4864277159499702126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=4864277159499702126' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/4864277159499702126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/4864277159499702126'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/09/scala-word-clouds.html' title='Scala Word Clouds'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-609270962363299370</id><published>2009-09-13T19:04:00.000-07:00</published><updated>2009-09-13T19:04:03.449-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Some Tasty Scala Sugar</title><content type='html'>I have finally been getting around to working some more on &lt;a href="http://code.google.com/p/scala-android/"&gt;Scala+Android&lt;/a&gt;. A lot needs to be done, especially since &lt;a href="http://www.siliconvalley-codecamp.com/Sessions.aspx?sortby=title&amp;amp;by=category&amp;amp;tag=232"&gt;I am talking about it next month at the Silicon Valley Code Camp&lt;/a&gt;. Scala advocates (and I guess that includes me) often say that is very easy for application developers to use Scala, i.e. that "most" developers are never exposed to the more complex aspects of the language. The folks who "suffer" are APIs developers. I've mostly fallen into the first camp (app developers), but now that I'm trying to create a Scala API on top of the Android SDK, I get exposed to more aspects of Scala. Here are a couple of things that I found interesting.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;One pattern that I particularly like is using inline objects as a substitute for flat properties. I picked this up from using &lt;a href="http://liftweb.net/"&gt;Lift&lt;/a&gt;'s Mapper/Record ORM. For example, if you are used to ORMs like Hibernate or Rails' ActiveRecord, you are used to using simple properties to map database columns. So if you had a user table with a name column, then the standard way to map this to a Java class would be like this:&lt;br /&gt;&lt;pre class="brush:java" name="code"&gt;@Entity class User{&lt;br /&gt;  private String name;&lt;br /&gt;  @Column public String getName() { return name; }&lt;br /&gt;  public void setName(String name) { this.name = name; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Clearly you could follow a similar pattern in Scala. However, Lift does the following:&lt;br /&gt;&lt;pre class="brush:scala" name="code"&gt;class User{&lt;br /&gt;  object name extends MappedString(this, 100)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Remember that in Scala, an object is a singleton (in this case, there will be a single instance of name per instance of User). Thus an object declaration is like a class declaration, hence it can extend another type (or multiple types, via Scala's traits.) So in this case, the subclassing provides type information about the name object. You also get methods on name courtesy of the subclassing.&lt;br /&gt;&lt;br /&gt;What is really cool is that you can declare methods on the object. Let's take an example of how this can be useful. A particularly useful class in Android is the ListView. It has a header and a footer, and has methods for adding child views to either the header or the footer. Here is some Scala sugar for this:&lt;br /&gt;&lt;pre class="brush:scala" name="code"&gt;class ListView(baseListView:android.widget.ListView){&lt;br /&gt;  object header {&lt;br /&gt;    def +=(v:View)=baseListView.addHeaderView(v)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;So now you can use this like: &lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;myListView.header += someOtherView &lt;br /&gt;&lt;/pre&gt;Very nice. But wait, there's more. ListView, as the name suggests, has a list of items. These items can be checked, and there are access methods: isItemChecked(position) and setItemChecked(position, isChecked). I wanted a method so that an application developer could do something like:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;if (myListView.items(i).checked) { // do something &lt;br /&gt;}&lt;br /&gt;// and for changing state&lt;br /&gt;myListView.items(i).checked = true&lt;br /&gt;&lt;/pre&gt;So how to do this? I got some help from Daniel Spiewak:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;class ListView(baseListView:android.widget.ListView){&lt;br /&gt;  def apply(position:Int) = new {&lt;br /&gt;    def checked = baseListView.isItemChecked(position)&lt;br /&gt;    def checked_=(isChecked:Boolean){&lt;br /&gt;      baseListView.setItemChecked(position,isChecked)&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Pretty cool, huh? I had never seen this syntax before. The apply method is "standard" sugar that let's treat the object as function, i.e. the parameters in the apply method look like they are parameters to the object. The = new {} is just like creating an anonymous class in Java. Next, I wanted to use this technique to manage child views in general. You see, ListView extends ViewGroup, which has generic addView methods. This method is overloaded. One version just takes a single view, so that's easy:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;class ViewGroup(base:android.view.ViewGroup){&lt;br /&gt;  object views {&lt;br /&gt;    def +=(v:View) = base.addView(v)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Pretty obvious at this point... However, another version of addView takes both a View and an insert into the ordered list. I thought that this kind of syntax would be intuitive:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;myListView.views(i) = someView&lt;br /&gt;&lt;/pre&gt;Here is how I coaxed that to work:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;class ViewGroup(base:android.view.ViewGroup){&lt;br /&gt;  object views {&lt;br /&gt;    def +=(v:View) = base.addView(v)&lt;br /&gt;    def update(index:Int,v:View) = base.addView(index, v)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This is another case of standard syntactic sugar in Scala. It allows exactly the syntax we wanted. Much thanks to both Daniel and to Steve Jenson for this tip.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-609270962363299370?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/609270962363299370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=609270962363299370' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/609270962363299370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/609270962363299370'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/09/some-tasty-scala-sugar.html' title='Some Tasty Scala Sugar'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-9040929634479112431</id><published>2009-09-01T17:49:00.001-07:00</published><updated>2009-09-01T18:10:00.716-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='metaprogramming'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Metaprogramming in Groovy and Scala</title><content type='html'>This morning I read an excellent &lt;a href="http://www.ibm.com/developerworks/java/library/j-pg06239.html"&gt;pair&lt;/a&gt; of &lt;a href="https://www.ibm.com/developerworks/java/library/j-pg08259.html"&gt;articles&lt;/a&gt; by Scott Davis on metaprogramming in Groovy. It reminded me of some of the different ways to approach this kind of problem. The second article in particular detailed a new feature in Groovy 1.6, the delegate annotation. Here is an example of using this feature:&lt;br /&gt;&lt;pre name="code" class="brush:groovy"&gt;&lt;br /&gt;public class Monkey {&lt;br /&gt; def eatBananas(){&lt;br /&gt;   println("gobble gulp")&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class RoboMonkey{&lt;br /&gt; @Delegate final Monkey monkey&lt;br /&gt; public RoboMonkey(Monkey m){&lt;br /&gt;   this.monkey = m&lt;br /&gt; }&lt;br /&gt; public RoboMonkey(){&lt;br /&gt;   this.monkey = new Monkey()&lt;br /&gt; }&lt;br /&gt; def crushCars(){&lt;br /&gt;   println("smash")&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This allows for the following usage:&lt;br /&gt;&lt;pre name="code" class="brush:groovy"&gt;&lt;br /&gt;def monkey = new RoboMonkey()&lt;br /&gt;monkey.eatBananas()&lt;br /&gt;monkey.crushCars()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What is interesting here is that you cannot just create a Monkey and call crushCars on it. RoboMonkey is meant to be a way to add functionality to the Monkey class (in this case the crushCars method), while still being able to treat the RoboMonkey as if it was a Monkey. I point this out because of how this would be done in Scala:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;&lt;br /&gt;class Monkey{&lt;br /&gt;  def eatBanaas = println("gobble gulp")&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RoboMonkey(val monkey:Monkey){&lt;br /&gt;  def this() = this(new Monkey)&lt;br /&gt;  def crushCars = println("smash")&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object Monkey{&lt;br /&gt;  implicit def makeRobo(monkey:Monkey):RoboMonkey = new RoboMonkey(monkey)&lt;br /&gt;  implicit def makeNormal(robo:RoboMonkey):Monkey = robo.monkey&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now arguably this is more complicated, because you have to create the Monkey object in addition to the Monkey class. What Scala requires is that you get those implicit functions (makeRobo, makeNormal) in scope. This is just one way to do that. The added benefit is the following usage:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;&lt;br /&gt; val monkey = new Monkey&lt;br /&gt; monkey.eatBanaas&lt;br /&gt; monkey.crushCars&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I guess the Groovy way to do this is to use the meta class:&lt;br /&gt;&lt;pre name="code" class="brush:groovy"&gt;&lt;br /&gt;Monkey.metaClass.crushCars =  {-&gt; println("smash")}&lt;br /&gt;def monkey = new Monkey()    &lt;br /&gt;monkey.eatBananas()&lt;br /&gt;monkey.crushCars()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In both languages you can accomplish similar things, though with very different ways to implement it. Meta programming in Groovy is very powerful, and there are things you can do in Groovy that you cannot do in Scala -- see &lt;a href="http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing"&gt;methodMissing and propertyMissing&lt;/a&gt;. Of course you lose some of the benefits of static typing, but software is all about tradeoffs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-9040929634479112431?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/9040929634479112431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=9040929634479112431' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/9040929634479112431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/9040929634479112431'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/09/metaprogramming-in-groovy-and-scala.html' title='Metaprogramming in Groovy and Scala'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-7034500171514117089</id><published>2009-08-30T11:36:00.000-07:00</published><updated>2009-08-30T13:03:54.793-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='user experience'/><category scheme='http://www.blogger.com/atom/ns#' term='usability'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='web applications'/><title type='text'>To Suggest or Not To Suggest</title><content type='html'>Ajax has been one of the most hyped technologies in recent memory. However, much of the hype is deserved. It really has changed the way we (web developers) build applications and the expectation of users. One of the archetypes of Ajax is the auto-suggest text box. I don't know who first came up with, but I first remember seeing it on Google. I think it was once a "special" version of the Google home page (Google Suggest?), but not it is standard:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XmwdENwf53s/SprJuoZqv8I/AAAAAAAAAp4/DJsYAJF8_jY/s1600-h/Screen+shot+2009-08-30+at+11.40.24+AM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 283px;" src="http://1.bp.blogspot.com/_XmwdENwf53s/SprJuoZqv8I/AAAAAAAAAp4/DJsYAJF8_jY/s400/Screen+shot+2009-08-30+at+11.40.24+AM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5375830908176351170" /&gt;&lt;/a&gt;&lt;br /&gt;It makes for a natural option on search text boxes. Here it is on some of the other search engines out there. Yahoo:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XmwdENwf53s/SprKSiVrzEI/AAAAAAAAAqA/dEsKXxHVJYY/s1600-h/Screen+shot+2009-08-30+at+11.41.30+AM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 79px;" src="http://2.bp.blogspot.com/_XmwdENwf53s/SprKSiVrzEI/AAAAAAAAAqA/dEsKXxHVJYY/s400/Screen+shot+2009-08-30+at+11.41.30+AM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5375831525024320578" /&gt;&lt;/a&gt;&lt;br /&gt;And on the search hotness, Bing:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XmwdENwf53s/SprKkYioeeI/AAAAAAAAAqI/9SNwlyIZC2I/s1600-h/Screen+shot+2009-08-30+at+11.42.23+AM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 195px;" src="http://2.bp.blogspot.com/_XmwdENwf53s/SprKkYioeeI/AAAAAAAAAqI/9SNwlyIZC2I/s400/Screen+shot+2009-08-30+at+11.42.23+AM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5375831831631919586" /&gt;&lt;/a&gt;&lt;br /&gt;Of course pure search engines are hardly the only sites that have search and thus have auto-suggest text boxes. It's pretty useful for ecommerce sites too...&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XmwdENwf53s/SprLxvUPQCI/AAAAAAAAAqQ/rrzJk6Q5bqo/s1600-h/Screen+shot+2009-08-30+at+11.43.42+AM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 329px; height: 339px;" src="http://2.bp.blogspot.com/_XmwdENwf53s/SprLxvUPQCI/AAAAAAAAAqQ/rrzJk6Q5bqo/s400/Screen+shot+2009-08-30+at+11.43.42+AM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5375833160595488802" /&gt;&lt;/a&gt;&lt;br /&gt;As you can see, some sites have gotten creative with their suggestions. Here is another great example of that from Apple:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XmwdENwf53s/SprMEX3RiuI/AAAAAAAAAqY/HpP0_CJ7EdM/s1600-h/Screen+shot+2009-08-30+at+11.46.10+AM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://3.bp.blogspot.com/_XmwdENwf53s/SprMEX3RiuI/AAAAAAAAAqY/HpP0_CJ7EdM/s400/Screen+shot+2009-08-30+at+11.46.10+AM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5375833480717503202" /&gt;&lt;/a&gt;&lt;br /&gt;All of these examples are for search text boxes. If what you want is not suggested, you can still type it and the application will perform a search on it. A little more interesting example is on Facebook:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XmwdENwf53s/SprVkta4deI/AAAAAAAAAqg/sndoVcp2a4s/s1600-h/Screen+shot+2009-08-30+at+12.38.23+PM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 252px;" src="http://3.bp.blogspot.com/_XmwdENwf53s/SprVkta4deI/AAAAAAAAAqg/sndoVcp2a4s/s400/Screen+shot+2009-08-30+at+12.38.23+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5375843931864462818" /&gt;&lt;/a&gt;&lt;br /&gt;Here there is a "closed list" behind the suggest box: your friends. However, it is still a search box. If you type something that is not in the list, it will still perform a search that will return results. Of course, really all of the suggest boxes have a closed list behind them as well, but that list is probably much bigger than your list of friends on Facebook (unless you are Robert Scoble.) So the theme continues: there is a finite set of predetermined suggestions, but if you type in something not in that set, the application can still process your input.&lt;br /&gt;Recently, I saw a different use for auto-suggest boxes: as a drop-in replacement for select/option boxes (a.k.a. drop-down box or combo box). This is fundamentally different than any of the examples above. It would be like the Facebook example, but with the limitation that your friends were the &lt;i&gt;only&lt;/i&gt; valid input into the search box. In fact, Facebook has a scenario that is similar to this: tagging people in photos/videos:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XmwdENwf53s/SprZTRgE-tI/AAAAAAAAAqo/3YbE8CAapvU/s1600-h/Screen+shot+2009-08-30+at+12.55.21+PM.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 227px;" src="http://2.bp.blogspot.com/_XmwdENwf53s/SprZTRgE-tI/AAAAAAAAAqo/3YbE8CAapvU/s400/Screen+shot+2009-08-30+at+12.55.21+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5375848030358797010" /&gt;&lt;/a&gt;&lt;br /&gt;However, even in this case, you can type the name of somebody who is not one of your friends. This is valid input. After all, maybe not everybody that you take pictures of has an account on Facebook. My kids are growing up fast, but my five year old son is not yet on Facebook...&lt;br /&gt;I imagine that this pattern -- using auto-suggest box to replace a select/option box -- is used on websites out there. It seems like a reasonable thing to do to avoid a drop-down with a large number of choices, or a drop-down that is expensive to calculate and is often not used. However, it seems awkward, too. What do you do when a user types in something that is not in the box? I like to type, and I'm both reasonably fast at it and make enough spelling mistakes that this could be a common scenario from me.&lt;br /&gt;Now I am no user experience expert. In fact, as a web developer, I would say that I am perhaps the least qualified person when it comes to judging user experience on the web. My knowledge makes me very forgiving of things that might be confusing to others, while it also makes me critical of things that others would not notice. So I am curious about other's people's experiences and opinions. Are there sites out there that use this pattern? Is it useful or awkward?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-7034500171514117089?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/7034500171514117089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=7034500171514117089' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/7034500171514117089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/7034500171514117089'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/08/to-suggest-or-not-to-suggest.html' title='To Suggest or Not To Suggest'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_XmwdENwf53s/SprJuoZqv8I/AAAAAAAAAp4/DJsYAJF8_jY/s72-c/Screen+shot+2009-08-30+at+11.40.24+AM.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-1009748217366955513</id><published>2009-08-15T03:18:00.000-07:00</published><updated>2009-08-15T04:22:22.891-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='intellij'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='netbeans'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>A Tipping Point for Scala</title><content type='html'>This past week's BASE meeting was all about IDE support for Scala. You can read &lt;a href="http://www.nabble.com/-scala-tools--Notes-from-Bay-Area-Scala-Enthusiasts-Meeting-on-Scala-IDE-td24969797.html"&gt;my notes&lt;/a&gt;, posted to the Scala tools mailing list. I was very surprised by this meeting. Not by the findings, if you will, as I have used all three IDEs at various times in the last few months. What I was surprised by was the feedback from the group, and the logical conclusion of this discussion: Scala is near a tipping point, but IDE support is holding it back.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First off, there was a large turnout for the BASE meeting. I would say it was the second largest BASE meeting, only bested by the June meeting where Martin Odersky spoke. It is funny, because I think our esteemed organizer, Dick Wall, had been intending this topic to be like "well if we have nothing else to talk about it, we'll talk about IDEs." If there had been an alternative topic brought up, I don't think people would have objected. After all, developers and their attitude towards IDEs are contradictory. Most developers I know would tell you that IDE support for a language is very important, but they would also act indifferent about IDEs when it came to them personally. It's like "all of those other developers really need IDEs, but I would be ok without them." We all know our APIs so well, that we don't need code completion, right? And we don't write bugs, so a debugger is of limited use, right? However, I am sure that if the meeting had not been about IDEs, then there would have been less people in attendance. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So why so much interest? Like it or not, but Scala's primary audience right now are Java developers. Yes, I know Scala appeals to some dynamic language folks, and to some functional programming folks, and that its .NET implementation is being updated, but you could sum up all of the Scala developers from those disciplines and it would be dwarfed by the Java contingency. Scala has a lot of appeal on its own merits, but it is always going to be framed against Java. Scala's most (only?) likely path to mass appeal is as "&lt;a href="http://macstrac.blogspot.com/2009/04/scala-as-long-term-replacement-for.html"&gt;the long term replacement for java&lt;/a&gt;." &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So when you talk about developers choosing to use Scala, you are really talking about Java developers choosing to use Scala instead of Java. This is not the only use case, but not only is it the most common use case, it is arguably the only use case that matters. Without this use case, Scala will at most be a marginal language, a la Haskell, or OCaml, or Groovy for that matter. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Back to my point... Java developers need great IDEs. This is not because they "need" help from their IDE because of some lack of skill. No, it's because they have had great IDEs for a long time now, and thus it has become a requirement. I remember when I joined Ludi Labs (it was still called Sharefare at the time) several years ago, we had a Java programming quiz. Candidates were given a clean install of Eclipse to use for writing their programs. We could have given them Vi or Emacs and a command line, but that would have been asinine and foolish. IDEs are an integral part of Java development.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I knew all of the above before the BASE meeting, but what I did not know was how many development organizations were at a critical juncture when it comes to Scala. For many folks, Scala, the language, has won the arguments. Whatever perceived extra complexity that it has, has been judged as worth it. Whatever challenges there may be in hiring people to develop in Scala can be mitigated. Legacy code is not even a factor, as integration with existing Java code is trivial.  Maybe it's bleak future of Java, or maybe it's the high profile use of Scala at Twitter. Who knows, but Scala is poised to take a big piece of the Java pie. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thus the missing piece is IDE support. Development orgs can't switch to Scala without IDE support, and the support is not there yet. That's the bad news. The good news is that Scala is ready to explode once the IDE support is there. There are a lot of folks out there ready to adopt Scala simply as a "better Java." They just need an IDE that is on par with Java IDEs. That is the standard. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All of that being said, there is a lot of concern around the IDEs. Many people expressed to me that they are worried that IDE progress is being coupled to the release of Scala 2.8. That seems reasonable at first, but what happens if 2.8 is not released until 2010 sometime? Will Scala lose its momentum and window of opportunity? &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-1009748217366955513?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/1009748217366955513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=1009748217366955513' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/1009748217366955513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/1009748217366955513'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/08/tipping-point-for-scala.html' title='A Tipping Point for Scala'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-3009763493915813651</id><published>2009-08-03T16:32:00.000-07:00</published><updated>2009-08-03T17:02:01.567-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>The Strange Loop</title><content type='html'>In October, I am speaking at &lt;a href="http://thestrangeloop.com/"&gt;the inaugural Strange Loop conference in St. Louis&lt;/a&gt;. This is not your run of the mill conference. It is organized by &lt;a href="http://tech.puredanger.com/"&gt;Alex Miller&lt;/a&gt;, who you might have seen speak the last couple of years at JavaOne. The speaker list is sweet: &lt;a href="http://al3x.net/"&gt;Alex Payne&lt;/a&gt; and &lt;a href="http://crazybob.org/"&gt;Bob Lee&lt;/a&gt; are doing the keynotes, with sessions by &lt;a href="http://blog.headius.com/"&gt;Charles Nutter&lt;/a&gt;, &lt;a href="http://deanwampler.com/"&gt;Dean Wampler&lt;/a&gt;, &lt;a href="http://stsmedia.net/category/programming/"&gt;Stefan Schmidt&lt;/a&gt;, &lt;a href="http://twitter.com/glaforge"&gt;Guillaume Laforge&lt;/a&gt;, &lt;a href="http://javajeff.blogspot.com/"&gt;Jeff Brown&lt;/a&gt;, and &lt;a href="http://www.doc.ic.ac.uk/%7Eabuckley/"&gt;Alex Buckley&lt;/a&gt;. I am doing a talk on iPhone/Android development. It will probably be pretty boring compared to the other sessions. I may try to spice it up with some shameless plugging of &lt;a href="http://code.google.com/p/scala-android/"&gt;Scala+Android&lt;/a&gt; balanced by some Fake Steve Jobs quotes about Android.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-3009763493915813651?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/3009763493915813651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=3009763493915813651' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3009763493915813651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/3009763493915813651'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/08/strange-loop.html' title='The Strange Loop'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-5386191302946156992</id><published>2009-07-31T20:13:00.000-07:00</published><updated>2009-07-31T20:40:47.287-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='terrorism'/><category scheme='http://www.blogger.com/atom/ns#' term='war and decision'/><category scheme='http://www.blogger.com/atom/ns#' term='iraq'/><category scheme='http://www.blogger.com/atom/ns#' term='9/11'/><category scheme='http://www.blogger.com/atom/ns#' term='feith'/><title type='text'>War and Decision</title><content type='html'>Recently I started reading Doug Feith's War and Decision.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img407.yfrog.com/img407/6566/qif.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 525px; height: 700px;" src="http://img407.yfrog.com/img407/6566/qif.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;I say "started reading" because I have not finished it yet. The book is about how the Bush Administration and in particular the Defense Department reacted to 9/11 and managed the wars in Afghanistan and Iraq. I have read most of the material on 9/11 and Afghanistan, but have not gone into the deeper material on Iraq.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I would highly recommend the book. Feith takes a very analytical approach that is full of insight and is though provoking. However, the book certainly has its faults. If you take the book as an extended position paper, then I would view these faults as fatal. If you take the book as a memoir, then these faults are perhaps the most valuable aspects of the narrative.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First off, Feith devotes a lot of the book to calling out statements by journalists and political opponents, and completely disproving these statements. From a literary perspective, this is easily the greatest weakness of the book. It is really beneath Feith to so painstakingly thumb his nose at detractors. How much joy can we really take in disproving pundits? This just in, journalists exaggerate and twist the truth in the quest for sensationalism...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I guess you can forgive Feith for all of this, as it must be frustrating to have to hear so many false claims in the press on a daily basis. Fine. However, the other mistake that Feith makes is not as annoying, but is in many was much worse. The funny part is that it is a mistake that, if we buy into Feith's characterizations, that his boss, Donald Rumsfeld, would have immediately pointed out. Feith claims to build up logical arguments for the decisions made by the Bush Administration, but he fails to point out the assumptions behind these decisions and their severe consequences. According to Feith, Rumsfeld was notorious for demanding to know the assumptions made by his analysts and advisors, hence the irony of Feith's prose.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The most basic and essential example of this is the reaction to the 9/11 attacks. Feith &amp;amp; co. immediately started thinking about how to broaden the response beyond just the perpetrators. This assumption, that the response needed to be broad, is hardly questioned. The only hand-waving given for it is that such a response would be more like a police action (punish the criminals) and thus ineffective. Justifications are only developed after the initial idea is pursued. For example, one justification is that a broad military action is the most likely way to prevent further attacks without negatively affecting the American way of life. Maybe this is true, the book is certainly thought provoking, but this justification is only developed ex post facto. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So more examples... Feith states that Iraq having WMDs was a given that everyone just accepted. He says that in late 2001 nobody would have argued that Iraq did not have WMDs. Feith also states that another given was that another 9/11-ish attack was imminent. It is not hard to see that if you start out assuming that the U.S. needed to make a broad military reaction, that Iraq had WMDs, and that devastating attacks were imminent, then you have to conclude the U.S. had to invade Iraq. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyways, I will reiterate that the book is good read, especially if you are an opponent of the war, as I am. Feith does admit early on that the Administration did not do a good job of communicating to the public. He underplays this (at least in the first third of the book or so, perhaps this changes.) Poor communication and an act of war have no place together in a democracy, at least in my opinion.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-5386191302946156992?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/5386191302946156992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=5386191302946156992' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/5386191302946156992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/5386191302946156992'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/07/war-and-decision.html' title='War and Decision'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-8640913259224946547</id><published>2009-07-19T11:39:00.000-07:00</published><updated>2009-07-19T12:29:05.622-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='lift'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>My HTML in Scala Wishlist</title><content type='html'>One of my favorite features in Scala is its &lt;a href="http://www.ibm.com/developerworks/library/x-scalaxml/"&gt;native support for XML&lt;/a&gt;(link warning, shameless plug.) I love the "projections DSL" (for lack of a better term) that is &lt;a href="http://www.scala-lang.org/docu/files/api/scala/xml$content.html"&gt;the scala.xml package&lt;/a&gt;. It is great for slicing up XML, and is almost like having native XPath and XQuery built into the language. Using XML in Scala for HTML generation is not as universally appealing to people. Some people think it encourages mixing presentation and business logic and is not "clean." I have even heard folks say that this is a critical flaw in Lift. I completely disagree. Of course I also think MVC is an anti-pattern, but anyways... HTML support in Scala is great in my opinion, but could be even better. Here is my wishlist.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Better understanding HTML semantics. For example, it is great that the compiler won't let me do something like this &amp;lt;div&gt;Hello world&amp;lt;/di&gt;. However, I would not want it to even let me do &amp;lt;di&gt;Hello world&amp;lt;/di&gt;. Similarly I should not be able to stick a thead outside of a table. If I have an anchor tag with an href attribute, then I'd like the compiler to do some validation on the value. Am I asking for too much? Well, that's I'm supposed to do, right? Is some/all of this possible with the help of XML schema support? Maybe so.&lt;/li&gt;&lt;li&gt;CSS. HTML without CSS ceased to exist a long time ago. With all of the DSL possibilities in Scala, is there some way to allow CSS literals and create some type safety for me. For example, I if I fat finger the name of a style on a class attribute, the compiler should catch this. Also I can say from experience that introducing an object-oriented model is really useful in CSS. Finally, the XPath/XQuery-like support in Scala XML makes me think that something similar could be done for CSS selectors.&lt;/li&gt;&lt;li&gt;JavaScript. Honestly I don't know what I would want here. I like JavaScript, but I know the idea of being able to write your web application in a single language is very appealing to a lot of people. If nothing else, it would once again be nice if the compiler would prevent me from doing something like &amp;lt;button onclick="foo()" ...&gt; if there as no function called "foo" in scope.&lt;/li&gt;&lt;li&gt;Tooling. Most modern IDEs support things like syntax highlighting, code completion, error checking, code formatting for HTML and XML+schema. I expect at least this much for XML/HTML literals in Scala. I'd also like to be able to step through and debug literals. Refactoring on subtrees of XML (extract method for example) would be sweet. Oh, and large XML literals should not overwhelm my IDE :-)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-8640913259224946547?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/8640913259224946547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=8640913259224946547' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/8640913259224946547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/8640913259224946547'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/07/my-html-in-scala-wishlist.html' title='My HTML in Scala Wishlist'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-4401476786770106063</id><published>2009-07-15T21:51:00.001-07:00</published><updated>2009-07-15T22:34:04.056-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='coca'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>Functional Paradigms on Android using Scala</title><content type='html'>I am slowly plugging away on &lt;a href="http://code.google.com/p/scala-android/"&gt;my little side project&lt;/a&gt;. One of the fun things about "pimping" an API, is you can tweak the design of the API. For example, I was modifying TextView, a class used for creating text input boxes of various sorts in Android. One common use case in Android is to create an auto-complete text box. To do this, you need to subclass TextView. Then you can override various lifecycle methods like onEditorAction, onKeyUp, etc. However, I thought that it might be nice to do something like this:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;&lt;br /&gt;val textView = new TextView&lt;br /&gt;textView.keyUp = (code:Int, event:KeyEvent) =&gt; {&lt;br /&gt;  // do stuff to your TextView&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As &lt;a href="http://twitter.com/debasishg/status/2664466894"&gt;Debasish pointed out to me&lt;/a&gt;, this is a lot like you would do in JavaScript. Is it better? It's a little easier in certain cases. If you just need to change the behavior of a single TextView in a very specific way, then this would seem like the way to go. Subclassing TextView just to override a single method and then using that subclass exactly once definitely seems like overkill. Now if you really wanted to create a new kind of TextView that you could use in multiple places, then subclassing makes sense.&lt;br /&gt;&lt;br /&gt;One thing worth mentioning is how this kind of thing is handled in Cocoa on the iPhone. The Cocoa way would be to create an untyped delegate. In the delegate you could override the lifecycle methods that you were interested in. It's untyped, so you have to know the right names. You still wind up defining a new class, even though you usually only want to customize the behavior of one particular instance. Also, it's a little clunky as the TextView instance would have to be passed in to each of the delegate methods, so that your delegate could actually do something to the TextView. I find this a little better than having to subclass as you do in Android, but once again I think using Scala can yield some nice results.&lt;br /&gt;&lt;br /&gt;There was another interesting case that popped up while sugaring TextView. I wanted to sugar the setCompoundDrawablesWithIntrinsicBounds methods. This method is overloaded, taking either four integers or four Drawables. Here is what I first thought of doing:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;&lt;br /&gt;def compoundDrawablesWithIntrinsicBounds_=(bounds:Tuple4[Int,Int,Int,Int]) {...}&lt;br /&gt;def compoundDrawablesWithIntrinsicBounds_=(bounds:Tuple4[Drawable,Drawable,Drawable,Drawable]) {...}&lt;br /&gt;// this allows&lt;br /&gt;myTextView.compoundDrawablesWithIntrinsicBounds = (1,2,3,4)&lt;br /&gt;// or&lt;br /&gt;myTextView.compoundDrawablesWithIntrinsicBounds = (d1,d2,d3,d4)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Of course this won't work. The type parameters of Tuple4 are going to be erased by the compiler, and the two methods are indistinguishable. However, &lt;a href="http://twitter.com/djspiewak/status/2662291832"&gt;The Amazing Mr. Spiewak gave me a solution&lt;/a&gt;:&lt;br /&gt;&lt;pre name="code" class="brush:scala"&gt;&lt;br /&gt;def compoundDrawablesWithIntrinsicBounds_=[T &lt;% Either[Int, Drawable]](bounds:Tuple4[T,T,T,T]){&lt;br /&gt; bounds._1 match {&lt;br /&gt;   case Left =&gt; baseTextView.setCompoundDrawablesWithIntrinsicBounds(bounds._1.left.get, bounds._2.left.get, &lt;br /&gt;                                                                      bounds._3.left.get, bounds._4.left.get)&lt;br /&gt;      case Right =&gt; baseTextView.setCompoundDrawablesWithIntrinsicBounds(bounds._1.right.get, bounds._2.right.get, &lt;br /&gt;                                                                      bounds._3.right.get, bounds._4.right.get)&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In addition to this, you need implicits to convert an Int to a Left and a Drawable to a Right. The API looks a lot different, but it allows exactly the same usage that I wanted. Another case of how you need some non-trivial Scala (though I wouldn't be surprised if there is a more elegant way than the above) to create an API that is super simple to use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-4401476786770106063?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/4401476786770106063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=4401476786770106063' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/4401476786770106063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/4401476786770106063'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/07/functional-paradigms-on-android-using.html' title='Functional Paradigms on Android using Scala'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-2287631401220774944</id><published>2009-07-08T15:27:00.000-07:00</published><updated>2009-07-08T16:06:20.271-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='webos'/><title type='text'>WebOS'es, Big Oil, and The Nutty Professor</title><content type='html'>I'm not going to talk about &lt;a href="http://googleblog.blogspot.com/2009/07/introducing-google-chrome-os.html"&gt;it&lt;/a&gt;. However, it reminds me of some things from my past...&lt;br /&gt;&lt;br /&gt;First, let me take you back to 2001. I was working for a start-up in the East Bay called RMX. We claimed to be the "Yahoo of convenience stores." In other words, we were a portal for owner/operators of convenience store/gasoline stations. We were backed by Chevron. All of their non-company stores used RMX to get data from Chevron, like when their next delivery of gas would be and how much it was going to cost them. They would also get &lt;a href="http://shop.ebay.com/?_nkw=chevron+cars"&gt;promotional stuff&lt;/a&gt; from Chevron and other &lt;a href="http://www.philipmorrisusa.com"&gt;folks&lt;/a&gt; who sold lots of &lt;a href="http://en.wikipedia.org/wiki/Cigarette"&gt;goods&lt;/a&gt; at convenience stores. Anyways, noticed I said non-company stores. Most gas stations selling Chevron gas are not owned by Chevron, they simply buy their gas from Chevron. Those stores were all required (by Chevron) to use RMX. Ch-ching. However, Chevron's so called "company owned, company operated" stores, or CoCos, did not use RMX :-( The reason? They did not have computers in these stores for fear that employees would waste time surfing the web and playing solitaire.&lt;br /&gt;&lt;br /&gt;Being a savvy start-up whose income was tied to the number of stores using our service, we came up with a clever idea. We built the first WebOS. Ok, so not really, but close. We built a Windows program that would take over the Windows shell. So no explorer.exe for you. The new shell, would embed an IE control with the page automatically opened to the RMX portal. There was no navigation bar, or bookmarks, etc. If you tried to leave the RMX portal, we'd catch it and send you back. If you tried to close the shell, it would reboot the computer. There was no escape! WebOS FTW!&lt;br /&gt;&lt;br /&gt;Anyways, many years later I would join another start-up called Sharefare (later renamed Ludi Labs.) Our goal was to build a WebOS! Our vision of a WebOS was a platform that handled all of your common tasks: email, bookmarks, photo/video/music management, blogging, etc. It was all through the web with all of your data stored in ... no not the cloud. We did not use that buzzword (maybe we should have.) Instead we had what we called a "cell architecture" and your data was stored in your cell. This was the brainchild of our founder/CEO, The Nutty Professor (Alan Bush, who is a great guy and brilliant to boot.) Our architecture was to have a UI layer on top of the WebOS. We called this the WebTop and that was my job. I wrote a programming language for the WebTop and implemented the language using a flammable combination of Java and JavaScript. It was a lot of fun, and probably the most academic exercise I will ever get to experience in my professional career. We never got to put it in the hands of customers, but at least I got a &lt;a href="http://www.wipo.int/pctdb/en/wo.jsp?WO=2008091705"&gt;patent&lt;/a&gt; out of it.&lt;br /&gt;&lt;br /&gt;So there, I've done the WebOS thing. Twice. Do people want this? I have no idea. In one case, we created a super-simplistic "OS", forced it on people, and did not care about their feedback (ok technically Chevron did the second two things.) In another case, we went for it all, but we never got the thing out the door, partially because it was a huge task.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-2287631401220774944?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/2287631401220774944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=2287631401220774944' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/2287631401220774944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/2287631401220774944'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/07/weboses-big-oil-and-nutty-professor.html' title='WebOS&apos;es, Big Oil, and The Nutty Professor'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5819005.post-4959266598915541596</id><published>2009-07-08T07:39:00.000-07:00</published><updated>2009-07-08T08:29:58.231-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mlb'/><category scheme='http://www.blogger.com/atom/ns#' term='sfgiants'/><category scheme='http://www.blogger.com/atom/ns#' term='baseball'/><title type='text'>Midseason Baseball Thoughts</title><content type='html'>It's the middle of the MLB season, and the All-Star Game is next week. This season has had its share of surprises so far. Since I live in the Bay Area, I must recognize the surprising season of the San Francisco Giants. They currently have the second best record in the National League. They are far back of the Dodgers, but would still be in the playoffs as the NL wildcard, if the season was over today. I have to admit that I keep wondering: are the Giants for real? The answer: Yes!&lt;br /&gt;&lt;br /&gt;Based on the Giants runs scored vs. runs allowed, the Giants expected wins at this point is 46.9. Their actual wins are 46. So they have not been "lucky" in terms of wins and losses. Their 303 runs allowed is the best in baseball. The pitching has been awesome. The offense has been middle of the pack, but hey that is not as bad as many (including me) expected.  So the Giants are for real because they have the best pitching in baseball. Will this continue to be true in the second half of the season?&lt;br /&gt;&lt;br /&gt;It is not a slam dunk. Lincecum is even more dominating this year than he was last year when he won the Cy Young. Some people worry that he is pitching too many innings given his age, but I won't jump on that bandwagon. He is one of the Giants' two All-Stars. The other is Matt Cain. Now I love Matt Cain. He is from Dothan, Alabama. That is just two hours north of my hometown in Florida, and is where my brother lives. However, Cain has been a little lucky this year. On balls put in play, Cain's batting average against is a little. Plus he's been lucky with stranding base runners. If this luck does not continue, then you can expect his hits allowed and runs allowed to both jump up a bit. Cain's a flyball pitcher too, so a jump in home runs allowed is always possible. Randy Johnson has been ok, but more importantly healthy. He just suffered his first injury of the season, which does not look like it will be too bad. However, it's hard to expect him to stay healthy the rest of the season. Barry Zito has been better than last year (which is not saying much) but could actually do even better in the second half. The fifth spot in the rotation has been in flux, so things could really only get better for that spot.&lt;br /&gt;&lt;br /&gt;Enough about the Giants... As for the rest of the NL. My favorite team, the Atlanta Braves, are mediocre and there's no reason to expect a lot different from them. The Phillies are better than their record, while the Marlins are a lot worse than their record. The Cardinals are also not quite as good as their record, but the rest of the NL Central is very mediocre. The Rockies have been a huge surprise, and they look a legitimate contender for the wildcard spot. They should be the strongest challenger to the Giants, and of course the two teams will get plenty of chances to play each other as they are both in the NL West.&lt;br /&gt;&lt;br /&gt;As for the AL, arguably the four best teams are all in the AL East. The Yankees have a nice lead in the wildcard over Tampa Bay. Still, Tampa Bay has proven that last year was not a fluke. The Yankees are definitely getting a nice ROI on all the money they spent on pitching. They are only a game back of Boston. Both teams look to improve in the second half. The Yankees will get three months of Alex Rodriguez, and the Red Sox's David Ortiz seems to have finally regained his form. The AL Central is a mess, with three pretty good teams within 2 games of each other. It's easy to count out Minnesota, but statistically they have been the best of the three teams. Finally, the AL West is a two horse race, and the two teams, LA and Texas, are statistically very even.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5819005-4959266598915541596?l=fupeg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fupeg.blogspot.com/feeds/4959266598915541596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5819005&amp;postID=4959266598915541596' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/4959266598915541596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5819005/posts/default/4959266598915541596'/><link rel='alternate' type='text/html' href='http://fupeg.blogspot.com/2009/07/midseason-baseball-thoughts.html' title='Midseason Baseball Thoughts'/><author><name>Michael Galpin</name><uri>http://www.blogger.com/profile/08698131967747444207</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06961976414990101307'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>