CINXE.COM

Neal Gafter's blog: March 2007

<!DOCTYPE html> <html xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/55013136-widget_css_bundle.css' rel='stylesheet' type='text/css'/> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='https://gafter.blogspot.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='http://gafter.blogspot.com/2007/03/' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Neal Gafter&#39;s blog - Atom" href="https://gafter.blogspot.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Neal Gafter&#39;s blog - RSS" href="https://gafter.blogspot.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Neal Gafter&#39;s blog - Atom" href="https://www.blogger.com/feeds/7803021/posts/default" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='http://gafter.blogspot.com/2007/03/' property='og:url'/> <meta content='Neal Gafter&#39;s blog' property='og:title'/> <meta content='Thoughts about Programming Languages, Science and Philosophy.' property='og:description'/> <title>Neal Gafter's blog: March 2007</title> <style id='page-skin-1' type='text/css'><!-- /* ----------------------------------------------- Blogger Template Style Name: Stretch Denim Designer: Darren Delaye URL: www.DarrenDelaye.com Date: 11 Jul 2006 ----------------------------------------------- */ body { background: #619bb8; margin: 0; padding: 0px; font: x-small Verdana, Arial; text-align: center; color: #000000; font-size/* */:/**/small; font-size: /**/small; } a:link { color: #215670; } a:visited { color: #215670; } a img { border-width: 0; } #outer-wrapper { font: normal normal 100% Verdana, Arial, Sans-serif;; } /* Header ----------------------------------------------- */ #header-wrapper { margin:0; padding: 0; background-color: #619bb8; text-align: left; } #header { margin: 0 2%; background-color: #215670; color: #efefef; padding: 0; font: normal normal 210% Verdana, Arial, Sans-serif;; position: relative; } h1.title { padding-top: 38px; margin: 0 1% .1em; line-height: 1.2em; font-size: 100%; } h1.title a, h1.title a:visited { color: #efefef; text-decoration: none; } #header .description { display: block; margin: 0 1%; padding: 0 0 40px; line-height: 1.4em; font-size: 50%; } /* Content ----------------------------------------------- */ .clear { clear: both; } #content-wrapper { margin: 0 2%; padding: 0 0 15px; text-align: left; background-color: #efefef; border: 1px solid #cccccc; border-top: 0; } #main-wrapper { margin-left: 1%; width: 64%; float: left; background-color: #efefef; display: inline; /* fix for doubling margin in IE */ word-wrap: break-word; /* fix for long text breaking sidebar float in IE */ overflow: hidden; /* fix for long non-text content breaking IE sidebar float */ } #sidebar-wrapper { margin-right: 1%; width: 29%; float: right; background-color: #efefef; display: inline; /* fix for doubling margin in IE */ word-wrap: break-word; /* fix for long text breaking sidebar float in IE */ overflow: hidden; /* fix for long non-text content breaking IE sidebar float */ } /* Headings ----------------------------------------------- */ h2, h3 { margin: 0; } /* Posts ----------------------------------------------- */ .date-header { margin: 1.5em 0 0; font-weight: normal; color: #666666; font-size: 100%; } .post { margin: 0 0 1.5em; padding-bottom: 1.5em; } .post-title { margin: 0; padding: 0; font-size: 125%; font-weight: bold; line-height: 1.1em; } .post-title a, .post-title a:visited, .post-title strong { text-decoration: none; color: #000000; font-weight: bold; } .post div { margin: 0 0 .75em; line-height: 1.3em; } .post-footer { margin: -.25em 0 0; color: #000000; font-size: 87%; } .post-footer .span { margin-right: .3em; } .post img, table.tr-caption-container { padding: 4px; border: 1px solid #cccccc; } .tr-caption-container img { border: none; padding: 0; } .post blockquote { margin: 1em 20px; } .post blockquote p { margin: .75em 0; } /* Comments ----------------------------------------------- */ #comments h4 { margin: 1em 0; color: #666666; } #comments h4 strong { font-size: 110%; } #comments-block { margin: 1em 0 1.5em; line-height: 1.3em; } #comments-block dt { margin: .5em 0; } #comments-block dd { margin: .25em 0 0; } #comments-block dd.comment-footer { margin: -.25em 0 2em; line-height: 1.4em; font-size: 78%; } #comments-block dd p { margin: 0 0 .75em; } .deleted-comment { font-style:italic; color:gray; } .feed-links { clear: both; line-height: 2.5em; } #blog-pager-newer-link { float: left; } #blog-pager-older-link { float: right; } #blog-pager { text-align: center; } /* Sidebar Content ----------------------------------------------- */ .sidebar h2 { margin: 1.6em 0 .5em; padding: 4px 5px; background-color: #619bb8; font-size: 100%; color: #333333; } .sidebar ul { margin: 0; padding: 0; list-style: none; } .sidebar li { margin: 0; padding-top: 0; padding-right: 0; padding-bottom: .5em; padding-left: 15px; text-indent: -15px; line-height: 1.5em; } .sidebar { color: #000000; line-height:1.3em; } .sidebar .widget { margin-bottom: 1em; } .sidebar .widget-content { margin: 0 5px; } /* Profile ----------------------------------------------- */ .profile-img { float: left; margin-top: 0; margin-right: 5px; margin-bottom: 5px; margin-left: 0; padding: 4px; border: 1px solid #cccccc; } .profile-data { margin:0; text-transform:uppercase; letter-spacing:.1em; font-weight: bold; line-height: 1.6em; font-size: 78%; } .profile-datablock { margin:.5em 0 .5em; } .profile-textblock { margin: 0.5em 0; line-height: 1.6em; } /* Footer ----------------------------------------------- */ #footer { clear: both; text-align: center; color: #000000; } #footer .widget { margin:.5em; padding-top: 20px; font-size: 85%; line-height: 1.5em; text-align: left; } /** Page structure tweaks for layout editor wireframe */ body#layout #header { width: 750px; } --></style> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=7803021&amp;zx=4238dace-1d46-4395-b90f-635feeb84b51' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=7803021&amp;zx=4238dace-1d46-4395-b90f-635feeb84b51' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> </head> <body> <div class='navbar section' id='navbar'><div class='widget Navbar' data-version='1' id='Navbar1'><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar/7803021?origin\x3dhttps://gafter.blogspot.com', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script><script type="text/javascript"> (function() { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = '//pagead2.googlesyndication.com/pagead/js/google_top_exp.js'; var head = document.getElementsByTagName('head')[0]; if (head) { head.appendChild(script); }})(); </script> </div></div> <div id='outer-wrapper'><div id='wrap2'> <!-- skip links for text browsers --> <span id='skiplinks' style='display:none;'> <a href='#main'>skip to main </a> | <a href='#sidebar'>skip to sidebar</a> </span> <div id='header-wrapper'> <div class='header section' id='header'><div class='widget Header' data-version='1' id='Header1'> <div id='header-inner'> <div class='titlewrapper'> <h1 class='title'> <a href='https://gafter.blogspot.com/'> Neal Gafter's blog </a> </h1> </div> <div class='descriptionwrapper'> <p class='description'><span>Thoughts about Programming Languages, Science and Philosophy.</span></p> </div> </div> </div></div> </div> <div id='content-wrapper'> <div id='main-wrapper'> <div class='main section' id='main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='blog-posts hfeed'> <div class="date-outer"> <h2 class='date-header'><span>Thursday, March 29, 2007</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post'> <a name='5793928125436653523'></a> <h3 class='post-title'> <a href='https://gafter.blogspot.com/2007/03/closures-for-organizing-your-code.html'>Closures for Organizing Your Code</a> </h3> <div class='post-header-line-1'></div> <div class='post-body'> <p><p>Much of the discussion of Closures in Java has been about they way they affect public APIs. But there is another aspect that is just as important: the way closures affect <em>private</em> APIs between parts of your program. Closures often enable a tremendous simplification of a program design compared to what would be required in their absence. The following describes my implementation of a graph algorithm for computing the<em> Jeffersonians</em> of a graph using algorithm K from Knuth's <em>The Art of Computer Programming</em>, volume 4B, section 7.5.7.</p> <p>As you may be aware the set of Jeffersonians of a graph is best computed using a complex recursive algorithm. Although recursive algorithms can be translated into algorithms without using recursion (Java without recursion remains Turing-complete), the recursive version of the algorithm is much shorter and easier to understand. We're lucky to be living in an age in which virtually all programming languages support recursion. Though details of the implementation are not important, my implementation went something like this:</p> <blockquote> <pre>public Collection&lt;Jeffersonian&gt; findAllJeffersonians(Graph g) { Collection&lt;Jeffersonian&gt; result = new ArrayList&lt;Jeffersonian&gt;(); findAllJeffersoniansInternal(g, result); return result; }</pre> </blockquote> <p>The idea is that the recursive part of the algorithm can pass around the collection into which the result will be placed, and every Jeffersonian that is found will be placed into the collection:</p> <blockquote> <pre>private void findAllJeffersoniansInternal(<br /> Graph g, Collection&lt;Jeffersonian&gt; result) {<br /> // complex recursive algorithm here<br /> Jeffersonian found = ...;<br /> result.add(found);<br /> // more complex recursion here<br />}</pre> </blockquote> <p>One pot of coffee and an all-nighter later I had this working like a charm. The next day my tech lead asked me to add an API element that determines whether or not a graph has a Jeffersonian or not. That was easy:</p> <blockquote> <pre>public boolean hasJeffersonian(Graph g) { return findAllJeffersonians(g).size() != 0; }</pre> </blockquote> <p>This didn't pass code review. The problem is that this new method is to be used in the inner loop of Google's &uuml;ber-secret application that will take over the world. Never mind that. The problem is performance. Determining whether or not a graph <em>has</em> a Jeffersonian can be done in linear time, but enumerating all of them requires quadratic time (or worse). But my implementation does it the hard way. By then it was Friday afternoon and I really wanted to head home for a glass of wine, so I did what any self-loathing software engineer would do: I cut and pasted the complex recursive code in <tt>findAllJeffersoniansInternal</tt> into <tt>hasJeffersonianInternal</tt> and added a boolean return value (true when a Jeffersonian was found). Then I added logic to short-circuit the rest of the algorithm once a Jeffersonian had been found at any step. The code was messy but workable, and I had it passing tests in less than an hour. The code duplication left me somewhat uncomfortable, but the two methods were different enough that merging them would have been hard. I considered adding a second flag so I could have one body of code to do both versions, but I decided to leave that refactoring until Monday. </p> <p>Something very strange happened over the weekend, though. On Monday my pointy-haired boss told me there was both good news and bad news, and asked which I wanted first. Knowing how these jokes work (the second one always trumps the first) I asked for the bad news first. The bad news was that my machine had crashed, losing all of my work from Friday. Including my implementation of <tt>hasJeffersonian</tt>. The good news was that my machine had been replaced with a brand new one, a fast new 40-core workstation, and it came with JDK7 preinstalled. I had been using JDK6 before, so I was eager to try the new Java language features. </p> <p>Taking a fresh look at the problem of writing <tt>hasJeffersonian</tt>, I decided to refactor the original program to pass a closure instead of a collection:</p> <blockquote> <pre>public Collection&lt;Jeffersonian&gt; findAllJeffersonians(Graph g) { Collection&lt;Jeffersonian&gt; result = new ArrayList&lt;Jeffersonian&gt;(); findAllJeffersoniansInternal(g, { Jeffersonian j =&gt; result.add(j); }); return result; }<br /><br />private void findAllJeffersoniansInternal(<br /> Graph g, {Jeffersonian =&gt; void} foundJeffersonian) {<br /> // complex recursive algorithm here<br /> Jeffersonian found = ...;<br /> foundJeffersonian.invoke(found);<br /> // more complex recursion here<br />}</pre> </blockquote> <p>Then I realized I could use the nicer syntax allowed for passing a closure to a method:</p> <blockquote> <pre>public Collection&lt;Jeffersonian&gt; findAllJeffersonians(Graph g) { Collection&lt;Jeffersonian&gt; result = new ArrayList&lt;Jeffersonian&gt;(); findAllJeffersoniansInternal(Jeffersonian j : g) { result.add(j); } return result; }</pre> </blockquote> <p>Solving the second problem was then trivial:</p> <blockquote> <pre>public boolean hasJeffersonian(Graph g) { findAllJeffersoniansInternal(Jeffersonian j : g) {<br /> return true;<br /> } return false; }</pre> </blockquote> <p>That was the entire implementation. I had a strange sense of elation, but I couldn't quite tell why. I could no longer remember why the problem was so messy on Friday. This refactoring seemed trivial, and this code was so clear. What made it so hard before? </p> <p>Then I woke up. It's 2007, not 2009. JDK7 is barely a gleam in the eye of Sun. My machine is only dual-core. Consensus on closures is elusive. As far as I can tell, there isn't any such thing as a graph's Jeffersonian, or a Google plan to take over the world. It's Monday morning, and I have to figure out how to merge two almost-copies of a big recursive algorithm.</p> <p>But on the bright side, my boss is a really nice guy.</p></p> <div style='clear: both;'></div> </div> <div class='post-footer'> <p class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/7803021/5793928125436653523' onclick=''>27 comments</a> </span> <span class='post-icons'> </span> <span class='post-backlinks post-comment-link'> </span> </p> <p class='post-footer-line post-footer-line-2'></p> <p class='post-footer-line post-footer-line-3'></p> </div> </div> </div> </div></div> <div class="date-outer"> <h2 class='date-header'><span>Friday, March 16, 2007</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post'> <a name='1766267659475005758'></a> <h3 class='post-title'> <a href='https://gafter.blogspot.com/2007/03/compact-object-comparator.html'>A Compact Object Comparator</a> </h3> <div class='post-header-line-1'></div> <div class='post-body'> <p><p>Every now and then a problem arises where the right solution would be to impose an arbitrary total ordering on a collection of objects. The simplest example of this is when you need to sychronize on more than one object, all at the same time, to maintain some consistency condition across those objects. Using <a href="http://www.javac.info/">Closures</a>, you might invoke a utility method like this: </p> <blockquote> <pre>Locks.withLocks(lock1, lock2) { // code protected by both locks }</pre> </blockquote> <p>To avoid deadlock, every piece of code that locks the same set of locks should do so in the same order. Rather than forcing all callers of the <code>withLocks</code> method to worry about getting them in the right order, the implementation of <code>withLocks</code> can sort the incoming locks. Then the caller can just pass the locks in arbitrary order, knowing that they will be locked &quot;in the right order&quot;. It doesn't actually matter what order we sort them in, as long as we always get the same order for the same objects. The implementation of <code>withLocks</code> can use <code>Collections.sort</code> to sort the incoming locks, but <code>java.util.concurrent.locks.Lock</code> is not naturally comparable, so we need to pass an appropriate comparator to <code>sort</code>. We need a <code>java.util.Comparator&lt;Lock&gt;</code>, but a <code>java.util.Comparator&lt;Object&gt;</code> would work just as well. Let's specify, and then implement, a suitable comparator. Here is what we need:</p> <blockquote> <pre>/** * Returns a comparator that imposes a complete order on all objects. * Each invocation of this method may yield a distinct comparator, * or may yield the same comparator. */ public Comparator&lt;Object&gt; totalOrder() { ... }</pre> </blockquote> <p>How are we going to do this? One idea is to create an assignment of long values to each object, as needed. That would look something like this: <blockquote> <p> <pre>public Comparator&lt;Object&gt; totalOrder() { return new TotalOrder(); } private class TotalOrder implements Comparator&lt;Object&gt; { long nextNonce = 1; Map&lt;Object,Long&gt; codes = new IdentityHashMap&lt;Object,Long&gt;(); public int compare(Object o1, Object o2) { Long l1 = getNonce(o1); Long l2 = getNonce(o2); return l1.compareTo(l2); } synchronized Long getNonce(Object o) { Long nonce = codes.get(o); if (nonce == null) { nonce = nextNonce++; codes.put(o, nonce); } return nonce; } }</pre> </blockquote> <p>There are two major problems with this approach. First, it causes object retention. Objects whose space would otherwise be recovered by the garbage collector are retained because they are reachable as keys in the <code>codes</code> map. We can't fix this by simply using a <code>WeakHashMap</code>; without the identity semantics of <code>IdentityHashMap</code> the technique doesn't work. We really need <code>WeakIdentityHashMap</code> for this, but no such class exists in the JDK yet. Fortunately, <a href="http://crazybob.org/">&quot;crazy&quot; Bob Lee</a> has come to the rescue with an <a href="http://google-guice.googlecode.com/svn/trunk/src/com/google/inject/util/ReferenceMap.java">implementation of this concept </a> inside the recently open-sourced <a href="http://code.google.com/p/google-guice/">Guice dependency injection framework</a>. I think this belongs in the JDK, and now is the time to propose it for JDK7. </p> <p>The other problem with this implementation is that this utility takes up too much space. In general, every time you call the <code>compare</code> method one or two objects might be created and added to the map.</p> <p>Another idea for implementing this utility is to sort the objects based on their <em>identity hash code</em>. Identity hash codes are well distributed, almost like random numbers. That is naturally thread-safe, and would look something like this: </p> <blockquote> <p> <pre>private class TotalOrder implements Comparator&lt;Object&gt; { public int compare(Object o1, Object o2) { if (o1==o2) return 0; int i1 = System.identityHashCode(o1); int i2 = System.identityHashCode(o2); return (i1&lt;i2) ? -1 : (i1==i2) ? 0 : 1; } }</pre> </blockquote> <p>This is much more compact than the previous approach. But because identity has codes are not guaranteed to be unique, it occasionally treats two distinct objects as equal.</p> <p>We can get the best of both worlds - a space-efficient comparator and a complete order - by combining the two approaches:</p> <blockquote> <p> <pre>private class TotalOrder implements Comparator&lt;Object&gt; { long nextNonce = 1; Map&lt;Object,Long&gt; codes = new IdentityHashMap&lt;Object,Long&gt;(); synchronized Long getNonce(Object o) { Long nonce = codes.get(o); if (nonce == null) { nonce = nextNonce++; codes.put(o, nonce); } return nonce; } public int compare(Object o1, Object o2) { if (o1==o2) return 0; int i1 = System.identityHashCode(o1); int i2 = System.identityHashCode(o2); if (i1 != i2) return (i1&lt;i2) ? -1 : 1; Long l1 = getNonce(o1); Long l2 = getNonce(o2); return l1.compareTo(l2); } }</pre> </blockquote> <p>By the way, if you haven't already checked it out, see <a href="http://crazybob.org/">&quot;crazy&quot; Bob Lee</a>'s <a href="http://code.google.com/p/google-guice/">Guice dependency injection framework</a>. We use it extensively at Google. By really taking advantage of recent language features such as generics and annotations, the Guice framework is very flexible and yet much <a href="http://code.google.com/p/google-guice/wiki/SpringComparison">simpler than existing frameworks</a>. <a href="http://stuffthathappens.com/blog/2007/03/09/guicy-good/">Throw away your XML</a> and write your Java code in Java! </p> <blockquote> <p><font size=small>thanks to <a href="http://crazybob.org/">&quot;crazy&quot; Bob Lee</a> for contributing the Guice framework, and for reviewing this essay. </font></p> </blockquote></p> <div style='clear: both;'></div> </div> <div class='post-footer'> <p class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/7803021/1766267659475005758' onclick=''>6 comments</a> </span> <span class='post-icons'> </span> <span class='post-backlinks post-comment-link'> </span> </p> <p class='post-footer-line post-footer-line-2'></p> <p class='post-footer-line post-footer-line-3'></p> </div> </div> </div> </div></div> <div class="date-outer"> <h2 class='date-header'><span>Thursday, March 08, 2007</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post'> <a name='1186772807314868796'></a> <h3 class='post-title'> <a href='https://gafter.blogspot.com/2007/03/on-expressive-power-of-programming.html'>On The Expressive Power of Programming Languages</a> </h3> <div class='post-header-line-1'></div> <div class='post-body'> <p><p>There are at least three separate proposals recently put forward in the space of &quot;Closures for Java.&quot; Among the criteria for evaluating the proposals, I'd like to discuss two: <em>conciseness</em> (possibly phrased as <em>convenience</em>) of code using the construct, and <em>expressiveness</em>. Conciseness is pretty obvious, and you can compare the proposals on this measure by writing snippets of code that do basically the same thing as each other, but written using existing constructs and then each of the proposed constructs. How many characters, or tokens, does it take to write the code? By the measure of conciseness, shorter is better. </p> <p>Unfortunately, the authors of the various proposals don't appear to be using a common meaning for &quot;expressiveness&quot; or &quot;expressive power.&quot; Consequently, we often end up talking at cross-purposes when comparing the proposals. Some people appear to treat &quot;expressiveness&quot; and &quot;conciseness&quot; as synonyms, but to me these have completely different meanings. Expressiveness is a bit harder to measure, but in some ways more important at this stage of the discussion. See Matthias Felleisen's, <em>On the Expressive Power of Programming Languages</em>, 3rd European Symposium on Programming, Copenhagen, Denmark, 1990, <a href="http://citeseer.ist.psu.edu/felleisen90expressive.html">http://citeseer.ist.psu.edu/felleisen90expressive.html</a>, for one attempt to formally capture the meaning of expressiveness.</p> <p>In my mind, a language construct is <em> expressive</em> if it enables you to write (and use) an API that can't be written (and used) without the construct. In the context of the <em><a href="http://www.javac.info/">Closures for Java</a></em> proposed language extension, <a href="http://www.bejug.org/confluenceBeJUG/display/PARLEYS/Closures+for+Java">control abstraction APIs</a> are the kind of thing that don't seem to be supported by the competing proposals. You don't see the proposals compared side-by-side on this measure because this is something only supported by one proposal. Programmers who have become accustomed to programming with closures find them very useful for factoring out common code in ways that are not currently possible in Java. See, for example, <a href="http://www.joelonsoftware.com/items/2006/08/01.html" rel="nofollow">http://www.joelonsoftware.com/items/2006/08/01.html</a>, <a href="http://ivan.truemesh.com/archives/000637.html" rel="nofollow">http://ivan.truemesh.com/archives/000637.html</a>, <a href="http://www.talios.com/dear_java_i_need_closure.htm" rel="nofollow">http://www.talios.com/dear_java_i_need_closure.htm</a>, and <a href="http://blog.moertel.com/articles/2005/08/30/closures-and-the-professional-programmer" rel="nofollow">http://blog.moertel.com/articles/2005/08/30/closures-and-the-professional-programmer</a>. These kinds of uses might not occur to you if you're mainly a Java programmer, because Java doesn't reward you for thinking this way. But this is another example of expressive power. </p> <p>I'm not particularly attached to one syntax or another for closures. I don't mean to say that syntax isn't important. Anyone who knows the story of <em><a href="http://www.daimi.au.dk/~plesner/variance/">variance</a></em> and <em><a href="http://www.gafter.com/~neal/jot-wildcards.pdf">wildcards</a></em> knows how much I value a good surface syntax. Our proposal describes a particular syntax not because we believe it is the best possible syntax, but because it is hard to write a specific proposal without <em>some</em> syntax. Ultimately, I hope the closures issue becomes a JSR and the expert group takes its time to decide what surface syntax is best. But I believe that the expressiveness of the <a href="http://www.javac.info/">Closures for Java</a> proposal is the most important reason to consider doing anything in this space at all. If it is just a matter of a slightly more concise syntax, I'm not sure it is worth the trouble. </p></p> <div style='clear: both;'></div> </div> <div class='post-footer'> <p class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/7803021/1186772807314868796' onclick=''>13 comments</a> </span> <span class='post-icons'> </span> <span class='post-backlinks post-comment-link'> </span> </p> <p class='post-footer-line post-footer-line-2'></p> <p class='post-footer-line post-footer-line-3'></p> </div> </div> </div> </div></div> <div class="date-outer"> <h2 class='date-header'><span>Monday, March 05, 2007</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post'> <a name='5778577199465199188'></a> <h3 class='post-title'> <a href='https://gafter.blogspot.com/2007/03/java-closures-versus-mouselistener.html'>Java Closures versus MouseListener</a> </h3> <div class='post-header-line-1'></div> <div class='post-body'> <p><p>The <a href="http://www.javac.info/">Closures for Java</a> proposal simplifies the code for many purposes where anonymous class instance creation expressions are currently used. When the anonymous class's supertype is an interface with a single abstract method, a closure can be used directly. But if the supertype is a class, like <tt>java.util.TimerTask</tt>, or has more than one method, like <tt>java.awt.event.MouseListener</tt>, then you can't use a closure directly. You can still use an anonymous inner class directly, as always, but there are ways of using closures that may be more convenient. For <tt>TimerTask</tt>, a client can be written this way <br /> </p> <pre><blockquote>void printHelloAfterDelay(java.util.Timer timer, long delay) { timer.schedule(TimerTask.of({ =&gt; System.out.println(&quot;Hello&quot;); }), delay); }</blockquote></pre> <p>if we add the following utility method to <tt>TimerTask</tt>: </p> <pre><blockquote><p>public TimerTask of(final Runnable block) { class ClosureTimerTask extends TimerTask {<br /> public void run() { block.run(); }<br /> }<br /> return new ClosureTimerTask(); }</p></blockquote></pre> <p>Similarly, Peter von der Ah&eacute; showed me how to use the builder pattern, along with closures, to simplify handling mouse events:</p> <pre><blockquote>void addSomeActions(java.awt.Component foo) { foo.addMouseListener(new MouseListenerBuilder() .setMouseClicked({ MouseEvent e => System.out.println("Mouse clicked"); }) .setMouseReleased({ MouseEvent e => System.out.println("Mouse released"); }) .setMouseEntered({ MouseEvent e => System.out.println("Mouse entered " + e.getComponent()); })); }</blockquote></pre> <p>The implementation of <tt>MouseListenerBuilder</tt> is left as an exercise to the reader. </p></p> <div style='clear: both;'></div> </div> <div class='post-footer'> <p class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/7803021/5778577199465199188' onclick=''>13 comments</a> </span> <span class='post-icons'> </span> <span class='post-backlinks post-comment-link'> </span> </p> <p class='post-footer-line post-footer-line-2'></p> <p class='post-footer-line post-footer-line-3'></p> </div> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='https://gafter.blogspot.com/search?updated-max=2007-05-26T10:07:00-07:00&amp;max-results=2&amp;reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'>Newer Posts</a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='https://gafter.blogspot.com/search?updated-max=2007-03-05T21:24:00-08:00&amp;max-results=2' id='Blog1_blog-pager-older-link' title='Older Posts'>Older Posts</a> </span> <a class='home-link' href='https://gafter.blogspot.com/'>Home</a> </div> <div class='clear'></div> <div class='blog-feeds'> <div class='feed-links'> Subscribe to: <a class='feed-link' href='https://gafter.blogspot.com/feeds/posts/default' target='_blank' type='application/atom+xml'>Posts (Atom)</a> </div> </div> </div></div> </div> <div id='sidebar-wrapper'> <div class='sidebar section' id='sidebar'><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <h2>Blog Archive</h2> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2024/'> 2024 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2024/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2023/'> 2023 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2023/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2020/'> 2020 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2020/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2019/'> 2019 </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2019/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2019/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2017/'> 2017 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2017/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2016/'> 2016 </a> <span class='post-count' dir='ltr'>(7)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2016/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2016/01/'> January </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2015/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2014/'> 2014 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2014/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2010/'> 2010 </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2010/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2010/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2009/'> 2009 </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2009/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2009/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/'> 2008 </a> <span class='post-count' dir='ltr'>(4)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/'> 2007 </a> <span class='post-count' dir='ltr'>(18)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> <ul class='posts'> <li><a href='https://gafter.blogspot.com/2007/03/closures-for-organizing-your-code.html'>Closures for Organizing Your Code</a></li> <li><a href='https://gafter.blogspot.com/2007/03/compact-object-comparator.html'>A Compact Object Comparator</a></li> <li><a href='https://gafter.blogspot.com/2007/03/on-expressive-power-of-programming.html'>On The Expressive Power of Programming Languages</a></li> <li><a href='https://gafter.blogspot.com/2007/03/java-closures-versus-mouselistener.html'>Java Closures versus MouseListener</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2006/'> 2006 </a> <span class='post-count' dir='ltr'>(20)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2006/12/'> December </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2006/11/'> November </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2006/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2006/09/'> September </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2006/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2005/'> 2005 </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2005/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2004/'> 2004 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2004/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> </div> </div> <div class='clear'></div> </div> </div><div class='widget Profile' data-version='1' id='Profile1'> <h2>About Me</h2> <div class='widget-content'> <dl class='profile-datablock'> <dt class='profile-data'> <a class='profile-name-link g-profile' href='https://www.blogger.com/profile/08579466817032124881' rel='author' style='background-image: url(//www.blogger.com/img/logo-16.png);'> Neal Gafter </a> </dt> <dd class='profile-textblock'>Neal Gafter is a Computer Programming Language Designer and Implementer, Amateur Scientist and Philosopher. He works on the Rel compiler at Relational.AI. He previously worked for Microsoft on C#, for Google on Calendar, and for Sun Microsystems on Java. Neal was granted an OpenJDK Community Innovators' Challenge award for his design and implementation of lambda expressions for Java. He is coauthor of <em>Java Puzzlers: Traps, Pitfalls, and Corner Cases</em> (Addison Wesley, 2005). He was a member of the C++ Standards Committee and led the development of C and C++ compilers at Sun Microsystems, Microtec Research, and Texas Instruments. He holds a Ph.D. in computer science from the University of Rochester.</dd> </dl> <a class='profile-link' href='https://www.blogger.com/profile/08579466817032124881' rel='author'>View my complete profile</a> <div class='clear'></div> </div> </div></div> </div> <!-- spacer for skins that want sidebar and main to be the same height--> <div class='clear'>&#160;</div> </div> <!-- end content-wrapper --> <div id='footer-wrapper'> <div class='footer no-items section' id='footer'></div> </div> </div></div> <!-- end outer-wrapper --> <script src="//www.google-analytics.com/urchin.js" type="text/javascript"> </script> <script type='text/javascript'> _uacct = "UA-605497-1"; urchinTracker(); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/1812387825-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY5GKt7l3xuLkrTeikm3XcK18PjcRA:1742550210764';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d7803021','//gafter.blogspot.com/2007/03/','7803021'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '7803021', 'title': 'Neal Gafter\x27s blog', 'url': 'https://gafter.blogspot.com/2007/03/', 'canonicalUrl': 'http://gafter.blogspot.com/2007/03/', 'homepageUrl': 'https://gafter.blogspot.com/', 'searchUrl': 'https://gafter.blogspot.com/search', 'canonicalHomepageUrl': 'http://gafter.blogspot.com/', 'blogspotFaviconUrl': 'https://gafter.blogspot.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': false, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': '', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': false, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Neal Gafter\x26#39;s blog - Atom\x22 href\x3d\x22https://gafter.blogspot.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Neal Gafter\x26#39;s blog - RSS\x22 href\x3d\x22https://gafter.blogspot.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Neal Gafter\x26#39;s blog - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/7803021/posts/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/459db401c2dc748e', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'archive', 'pageName': 'March 2007', 'pageTitle': 'Neal Gafter\x27s blog: March 2007'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'custom', 'localizedName': 'Custom', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': true}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Neal Gafter\x27s blog', 'description': 'Thoughts about Programming Languages, Science and Philosophy.', 'url': 'https://gafter.blogspot.com/2007/03/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2007, 'month': 3, 'rangeMessage': 'Showing posts from March, 2007'}}}]); _WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/791292575-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/1964470060-lightbox_bundle.css'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_ProfileView', new _WidgetInfo('Profile1', 'sidebar', document.getElementById('Profile1'), {}, 'displayModeFull')); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10