CINXE.COM
Neal Gafter's blog: 2008
<!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/2008/' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Neal Gafter's blog - Atom" href="https://gafter.blogspot.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Neal Gafter's blog - RSS" href="https://gafter.blogspot.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Neal Gafter'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/2008/' property='og:url'/> <meta content='Neal Gafter's blog' property='og:title'/> <meta content='Thoughts about Programming Languages, Science and Philosophy.' property='og:description'/> <title>Neal Gafter's blog: 2008</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&zx=ec521dc9-f6a0-4bc7-9244-fe69ed71716a' media='none' onload='if(media!='all')media='all'' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=7803021&zx=ec521dc9-f6a0-4bc7-9244-fe69ed71716a' 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, August 07, 2008</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post'> <a name='3047255195011311765'></a> <h3 class='post-title'> <a href='https://gafter.blogspot.com/2008/08/java-closures-prototype-feature.html'>Java Closures Prototype Feature-Complete</a> </h3> <div class='post-header-line-1'></div> <div class='post-body'> <p><p>I'm pleased to announce that the Java Closures prototype now supports all of the features of its specification! <p>The complete source code, released under GPLv2, is in the project's openjdk repository. A binary build, suitable for use with an existing JDK6, is at <a href="http://www.javac.info/closures.tar.gz" >http://www.javac.info/closures.tar.gz</a>. Other related documents are on the website <a href="http://www.javac.info/" >http://www.javac.info/</a> <p>Although there is room for performance tuning, the prototype supports the full <a href="http://www.javac.info/closures-v05.html ">Closures (v0.5) specification</a>. Based on your feedback, there are some changes in the prototype suitable for a future update of the specification: <ul> <li>Renamed <code>Unreachable</code> to <code>Nothing</code></li> <blockquote> We adopt the name used by Scala to represent the same concept. </blockquote> <li>Removed support for the type <code>null</code></li> <blockquote> We used <code>null</code> as a placeholder for an exception type when none can be thrown. The type <code>Nothing</code> now serves that purpose; <code>null</code> is no longer supported as the name of a type. </blockquote> <li>Overhauled restricted versus unrestricted</li> <blockquote> In the specification, an interface is considered <em>restricted</em> if it extends a marker interface. Unfortunately, the specification only provides a syntax for function type interfaces that are unrestricted. We modified the syntax so that a function type written using the <code>=></code> token designates a restricted function type, while one written using the newly introduced <code>==></code> token represents an unrestricted function type. This allows programmers to easily write APIs that restrict (or don't restrict) the operations of closure expressions passed as parameters. </blockquote> <li>Refined restrictions</li> <blockquote> We modified the distinction between restricted and unrestricted closures. As before, it is not legal to convert an unrestricted closure to a restricted interface type, nor is it legal to <code>break</code>, <code>continue</code>, or <code>return</code> from inside a restricted closure to a target outside the closure. However, a restricted closure is allowed to refer to a non-final local variable from an enclosing scope. In this case a warning is given unless one of the following conditions holds: <ol> <li>The variable is not the target of any assignment, or</li> <li>The variable is annotated @Shared</li> </ol> <p>It is possible to suppress the warning by annotating some enclosing construct <code>@SuppressWarnings("shared")</code>. </blockquote> <li>Relaxed the closure conversion</li> <blockquote> In response to user feedback, we've relaxed the relationship between a closure parameter's type and the target interface's parameter type. Rather than requiring them to be of the same type, they are now allowed to be related by an assignment conversion, including boxing or unboxing. </blockquote> <li><code>for</code>-qualified method declarations</li> <blockquote> The <code>for</code> keyword on a method declaration, meant to introduce a control abstraction method that works like a loop, is now treated syntactically like a modifier rather than appearing immediately before the method name. This helps make the declaration site more similar to the use site. </blockquote> <li>Added support for method references</li> <blockquote> <p>We added extensive support for treating a reference to a method as a closure using a newly introduced token <code>#</code>. The syntax is borrowed from the <a href="http://docs.google.com/View?docid=ddhp95vd_6hg3qhc">FCM proposal</a>. The semantics are as follows:</p> <p>A method reference written as</p> <blockquote> <pre> <em>Primary</em> # <em>Identifier</em> ( <em>TypeList</em> ) </pre> </blockquote> <p>where the Primary designates an expression (as opposed to a type) is treated the same as a closure <blockquote> <pre> { Type x0, Type x1 ... => tmp.Identifier(x0, x1 ...) } </pre> </blockquote> or <blockquote> <pre> { Type x0, Type x1 ... => tmp.Identifier(x0, x1 ...); } </pre> </blockquote> <p>Where tmp is a temporary value that holds the computed value of the primary expression. The former translation is used when the resolved method has a non-void return type, while the latter is used when the resolved method has a void return type. <p>If the primary resolves to a type, then this is translated to <blockquote> <pre> { Type x0, Type x1 ... => Primary.Identifier(x0, x1 ...) } </pre> </blockquote> or <blockquote> <pre> { Type x0, Type x1 ... => Primary.Identifier(x0, x1 ...); } </pre> </blockquote> <p>when the resolved method is static, or <blockquote> <pre> { Primary x, Type x0, Type x1 ... => x.Identifier(x0, x1 ...) } </pre> </blockquote> or <blockquote> <pre> { Primary x, Type x0, Type x1 ... => x.Identifier(x0, x1 ...); } </pre> </blockquote> <p>when the resolved method is an instance method. <p>In addition, optional explicit type arguments, between angle brackets, may be placed immediately after the <code>#</code> token. These are used directly in the translated method invocation to resolve the method to be invoked. </blockquote> <li>Implemented a classfile format for the <code>for</code> qualifier</li> <blockquote> We've impleemnted a class file representation of the <code>for</code> qualifier to support separate compilation. </blockquote> </ul></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/3047255195011311765' onclick=''>42 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 17, 2008</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post'> <a name='7985322555245085577'></a> <h3 class='post-title'> <a href='https://gafter.blogspot.com/2008/03/closures-control-abstraction-method.html'>Closures: Control Abstraction, Method References, Puzzler Solution</a> </h3> <div class='post-header-line-1'></div> <div class='post-body'> <p><h1>Closures: Control Abstraction, Method References, Puzzler Solution</h1> <p>The Java Closures prototype now supports <em>control abstraction</em> and implements <em>restricted</em> closures and function types. The syntax has changed slightly. Also, as hinted in the <a href="http://www.javac.info/consensus-closures-jsr.html">draft JSR proposal</a>, there is now support for <em>eta abstraction</em>, which is called <em>method reference</em> in <a href="http://docs.google.com/View?docid=ddhp95vd_0f7mcns">Stephen Colebourne's FCM proposal</a>. We haven't updated the <a href="http://www.javac.info/">specification</a>, so this will serve as a brief tutorial on the changes until we do. I don't know if this will be the syntax we will end up with, but it will do for now. Finally, we look at solutions to the closure puzzler in my previous post.</p> <h3>Control Abstraction</h3> <p>The first thing you'll notice when using the new prototype is that the compiler gives a warning when a closure uses a local variable from an enclosing scope:</p> <blockquote> <pre>Example.java:4: warning: [shared] captured variable i not annotated @Shared Runnable r = { => System.out.println(i); }; ^ </pre> </blockquote> <p>There are a few ways to make this warning go away:</p> <ul> <li>declare the variable <code>final</code>; or</li> <li>annotate the variable <code>@Shared</code>; or</li> <li>make sure the variable is not the target of any assignment expression; or</li> <li>put <code>@SuppressWarnings("shared")</code> on an enclosing method or class; or</li> <li>use an <em>unrestricted</em> closure, by using the <code>==></code> token instead of the <code>=></code> token (when possible).</li> </ul> <p>The <code>=></code> token builds a <em>restricted</em> closure that triggers this warning. Restricted closures also do not allow a <code>break</code> or <code>continue</code> statement to a target outside the closure, nor a <code>return</code> statement from the enclosing method. You will rarely want to write an unrestricted closure; many (but not all) of the things you need to do with an unrestricted closure can be expressed more clearly with a <em>control invocation statement</em> instead.</p> <p>You're not allowed to assign an unrestricted closure to a restricted interface. A number of existing JDK interfaces, such as <code>java.lang.Runnable</code>, have been modified to be restricted<code></code>.</p> <blockquote> <pre>Error: cannot assign an unrestricted closure to a restricted interface type<br /> Runnable r = { ==> System.out.println(i); };<br /> ^</pre> </blockquote> <p></p> <p>In the less common case that you're writing a method intended to be used as a control API, you can write a function type with the (new) <code>==></code> token to designate an unrestricted function (interface) type. Let's do that to write a method, <code>with</code>, that will automatically close a stream for us. The idea is to be able to replace this code</p> <blockquote> <pre>FileInputStream input = new FileInputStream(fileName);<br />try {<br /> // use input<br />} finally {<br /> try {<br /> input.close();<br /> } catch (IOException ex) { logger.log(Level.SEVERE, ex.getMessage(), ex);<br /> }<br />}</pre> </blockquote> <p></p> <p>with this</p> <blockquote> <pre>with (FileInputStream input : new FileInputStream(fileName)) { // use input } </pre> </blockquote> <p>which is an invocation of the following method</p> <blockquote> <pre> public static void with(FileInputStream t, {FileInputStream==>void} block) {<br /> try {<br /> block.invoke(t);<br /> } finally {<br /> try {<br /> t.close();<br /> } catch (IOException ex) {<br /> logger.log(Level.SEVERE, ex.getMessage(), ex);<br /> }<br /> }<br />}</pre> </blockquote> <p>This is among the simplest control APIs, but it has some limitations:</p> <ul> <li>It works with the type <code>FileInputStream<code></code></code>, but not any other <code>Closeable</code> types</li> <li>It does not support <a href="http://tronicek.blogspot.com/2007/12/exceptions.html">exception transparency</a></li> <li>It does not support <a href="http://tronicek.blogspot.com/2008/01/completion-transparency.html">completion transparency</a></li> </ul> <p>Completing the API by repairing these defects is left as an exercise to the reader. A solution will be discussed in <a href="https://www28.cplan.com/cc191/session_details.jsp?isid=295579&ilocation_id=191-1&ilanguage=english">my JavaOne talk <em>Closures Cookbook</em></a>.</p> <h3>Method References</h3> <p>A natural companion to <em>closures</em> is a way to refer to an existing method instead of writing a closure that accepts the same arguments and just invokes the method. This is sometimes known as <a href="http://www.lambda-bound.com/book/lambdacalc/node22.html"><em>eta abstraction</em></a> or <a href="http://docs.google.com/View?docid=ddhp95vd_6hg3qhc"><em>method references</em></a>. We expect closures in their final form to include support for this convenient feature, which is why it is called out in the <a href="http://www.javac.info/consensus-closures-jsr.html">draft JSR proposal</a>. The latest version of the prototype supports this, with a syntax based on javadoc conventions. Here are a few examples:</p> <blockquote> <pre>{ int => Integer } integerValue = Integer#valueOf(int); { Integer => String } integerString = Integer#toString(); { int, int => int } min = Math#min(int, int); { String => void } println = System.out#println(String); { => String } three = new Integer(3)#toString(); { Collection<String> => String } max = Collections#max(Collection<String>); { => Collection<String> } makeEmpty = Collections#<String>emptySet(); Runnable printEmptyLine = System.out#println();</pre> </blockquote> <p>Writing code as a method is sometimes more convenient than writing it as a closure:</p> <blockquote> <pre>void doTask() { // a complex task to be done in the background } Executor ex = ...; ex.execute(<strong>this#doTask()</strong>);</pre> </blockquote> <h3>Puzzler Solution</h3> <p>A couple of weeks ago we looked at <a href="http://gafter.blogspot.com/2008/02/closures-puzzler-neapolitan-ice-cream.html">a Java puzzler involving closures</a>, and a number of people discussed the underlying issue. My favorite is <a href="http://www.chrononaut.org/showyourwork/?p=21">David's post "<em>Color-flavor locking breaks chiral symmetry"</em></a>. Lessons include not exposing public fields (accessors are better) and being careful to avoid cyclic initialization dependencies.</p> <p>The enum language feature provides support for one solution to the puzzle: specialize each instance of the enums.</p> <blockquote> <pre>import java.util.*; enum Color { BROWN { public Flavor flavor() { return Flavor.CHOCOLATE; } }, RED { public Flavor flavor() { return Flavor.STRAWBERRY; } }, WHITE { public Flavor flavor() { return Flavor.VANILLA; } }; abstract Flavor flavor(); } enum Flavor { CHOCOLATE { public Color color() { return Color.BROWN; } }, STRAWBERRY { public Color color() { return Color.RED; } }, VANILLA { public Color color() { return Color.WHITE; } }; abstract Color color(); } class Neapolitan { static <T,U> List<U> map(List<T> list, {T=>U} transform) { List<U> result = new ArrayList<U>(list.size()); for (T t : list) { result.add(transform.invoke(t)); } return result; } public static void main(String[] args) { List<Color> colors = map(Arrays.asList(Flavor.values()), { Flavor f => f.color() }); System.out.println(colors.equals(Arrays.asList(Color.values()))); List<Flavor> flavors = map(Arrays.asList(Color.values()), { Color c => c.flavor() }); System.out.println(flavors.equals(Arrays.asList(Flavor.values()))); } }</pre> </blockquote> <p>Another elegant solution, due to 5er_levart, uses closures:</p> <blockquote> <pre>enum Color { BROWN({=>Flavor.CHOCOLATE}), RED({=>Flavor.STRAWBERRY}), WHITE({=>Flavor.VANILLA}); private final {=>Flavor} flavor; public Flavor flavor() { return flavor.invoke(); } Color({=>Flavor} flavor) { this.flavor = flavor; } } enum Flavor { CHOCOLATE({=>Color.BROWN}), STRAWBERRY({=>Color.RED}), VANILLA({=>Color.WHITE}); private final {=>Color} color; public Color color() { return color.invoke(); } Flavor({=>Color} color) { this.color = color; } } </pre> </blockquote> <p>In both solutions the idea is to compute the value lazily, a key technique to break dependency cycles.</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/7985322555245085577' onclick=''>23 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>Tuesday, February 05, 2008</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post'> <a name='8792241959435745973'></a> <h3 class='post-title'> <a href='https://gafter.blogspot.com/2008/02/closures-puzzler-neapolitan-ice-cream.html'>Closures Puzzler: Neapolitan Ice Cream</a> </h3> <div class='post-header-line-1'></div> <div class='post-body'> <p><p> People experience the world in different ways, using different senses. Some people view the world primarily through sight. Do you see what I mean? Some through sound. Do you hear me? Some experience the world only after thought and reflection. Do you know what I mean? Some point out "smells" in code as a way of criticizing its design. This puzzle explores the question of whether people experiencing the same thing through different senses are really experiencing the same thing at all. What is the program's output, and why? </p> <p> This puzzle uses <a href="http://www.javac.info/">Java Closures</a>, so if you want to try it you should download the prototype <a href="http://www.javac.info/closures.tar.gz">here</a>. You can download the puzzle sources <a href="http://www.javac.info/Neapolitan.java">here</a>. Comments on this blog post will not be posted to avoid spoiling the puzzle. </p> <blockquote> <pre> import java.util.*; enum Color { BROWN(Flavor.CHOCOLATE), RED(Flavor.STRAWBERRY), WHITE(Flavor.VANILLA); final Flavor flavor; Color(Flavor flavor) { this.flavor = flavor; } } enum Flavor { CHOCOLATE(Color.BROWN), STRAWBERRY(Color.RED), VANILLA(Color.WHITE); final Color color; Flavor(Color color) { this.color = color; } } class Neapolitan { static <T,U> List<U> map(List<T> list, {T=>U} transform) { List<U> result = new ArrayList<U>(list.size()); for (T t : list) { result.add(transform.invoke(t)); } return result; } public static void main(String[] args) { List<Color> colors = map(Arrays.asList(Flavor.values()), { Flavor f => f.color }); System.out.println(colors.equals(Arrays.asList(Color.values()))); List<Flavor> flavors = map(Arrays.asList(Color.values()), { Color c => c.flavor }); System.out.println(flavors.equals(Arrays.asList(Flavor.values()))); } } </pre> </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/8792241959435745973' onclick=''>1 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, January 11, 2008</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post'> <a name='4922325604477316744'></a> <h3 class='post-title'> <a href='https://gafter.blogspot.com/2008/01/is-java-dying.html'>Is the Java Language Dying?</a> </h3> <div class='post-header-line-1'></div> <div class='post-body'> <p><p>We tend to think of programming languages in two categories: "living languages" in which we should seriously consider developing new code, and "legacy languages" that we mainly use, if at all, because we have to maintain an existing code base. The act of classifying a language into one or the other category helps us decide what, if anything, we might consider doing to change the language. If a language is primarily a legacy language, changes should be aimed at making it easier to maintain and modify existing bodies of code. A living language, on the other hand, also benefits from changes that make it easier to design, develop, and maintain new code. Living languages evolve to reduce <i>accidental complexity</i>. <blockquote>"What does a high-level language accomplish? It frees a program from much of its accidental complexity. An abstract program consists of conceptual constructs: operations, datatypes, sequences, and communication. The concrete machine program is concerned with bits, registers, conditions, branches, channels, disks, and such. To the extent that the high-level language embodies the constructs wanted in the abstract program and avoids all lower ones, it eliminates a whole level of complexity that was never inherent in the program at all." -<em><a href="http://info.computer.org/portal/site/computer/menuitem.eb7d70008ce52e4b0ef1bd108bcd45f3/index.jsp?&path=computer/homepage/misc/Brooks&file=index.xml&xsl=article.xsl&">No Silver Bullet - Fred Brooks</a> </em> </blockquote> <p>Programs written in legacy languages tend to exhibit a high degree of accidental complexity <a href="http://steve-yegge.blogspot.com/2007/12/codes-worst-enemy.html">[<i>Code's Worst Enemy</i>, Steve Yegge]</a> <a href="http://bc-squared.blogspot.com/2007/12/mr-yegge-meets-mr-brooks.html">[<i>Mr. Yegge meets Mr. Brooks</i>, Brian C Cunningham]</a>. Early in the life of a language, the complexity of programs written in that language may appear to be essential, but as we learn more about software engineering and programming languages, we find patterns of complexity appearing in the code that can be eliminated by improved languages. <p>A good example of this is garbage collection. In C and C++, memory management is a pervasive concern. Smart pointers and destructors help, but they do not significantly reduce the complexity of memory management. In languages with garbage collection, most of the complexity of memory management is assumed by the implementation of the language. Most languages that have been introduced in the past ten years support garbage collection. <p>Another example is concurrency. The threads-and-locks-and-semaphores primitives of Java enable parallel programming, but require that programmers express concurrency at a fairly low level. This has been "good enough" for some time, as most programs are not deployed on highly concurrent hardware. But that is changing [<a href="http://www.gotw.ca/publications/concurrency-ddj.htm"><i>The Free Lunch Is Over</i>, Herb Sutter]</a>. Libraries such as <a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html">java.util.concurrent</a> and <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166ydocs/">Doug Lea's fork-join framework</a> help somewhat, but in many cases they introduce complexities of their own. Other languages that support closures, such as <a href="http://www.scala-lang.org/">Scala</a> make fork-join-like libraries much easier to use. Scala supports <a href="http://portal.acm.org/citation.cfm?id=177584&dl=GUIDE&coll=GUIDE&CFID=10370783&CFTOKEN=82858580"><i>control abstraction</i> [Crowl and LeBlanc]</a>, which allows the <a href="http://debasishg.blogspot.com/2006/11/threadless-concurrency-on-jvm-aka-scala.html">libraries to manage much of the complexity associated with concurrency [Debasish Ghosh]</a>. <a href="http://lampwww.epfl.ch/%7Eodersky/papers/jmlc06.pdf">Support</a> for the <a href="http://lamp.epfl.ch/%7Ephaller/doc/haller07coord.pdf">Actors model [Haller and Odersky]</a>, for example, can be expressed cleanly as <a href="http://lamp.epfl.ch/%7Ephaller/actors.html">a library in Scala</a> <p>Besides <a href="http://portal.acm.org/citation.cfm?id=177584&dl=GUIDE&coll=GUIDE&CFID=10370783&CFTOKEN=82858580">raising the level of abstraction of concurrent code</a>, control abstraction also raises the level of abstraction for sequential code by <a href="http://www.parleys.com/display/PARLEYS/An+update+on+Java+Closures">eliminating whole categories of boilerplate, which can instead be moved into common library code</a>. This kind of boilerplate cannot be significantly reduced by adding one or two custom statements to the language, because such built-in forms necessarily make assumptions about the use cases that narrow their applicability. For example, <a href="http://docs.google.com/View?docid=dffxznxr_1nmsqkz">ARM blocks</a> don't document how they handle exceptions arising from the close() method. One example in the proposal suggests they are silently swallowed at runtime, which may work for many cases involving I/O streams, but another example given is a transactional API, in which ignoring such exceptions is precisely wrong. Without a specification for the syntax and semantics, the reader is welcome to imagine the most favorable treatment of each use case. But <a href="http://markmahieu.blogspot.com/2008/01/cicearm-observations.html">an attempt to reconcile these and other conflicting requirements may show the approach cannot be salvaged</a>. Perhaps that is why no progress has been made since mid 2006. <p>What about Java? Is it a living language, or <a href="http://www.infoworld.com/article/07/12/28/52FE-underreported-java_1.html">a legacy language like Cobol</a>? This question underlies much of the debate about how to move the Java programming language forward, if at all. Carl Quinn asked at the December 14, 2007, JavaPolis Future of Computing Panel (to be published on <a href="http://www.parleys.com/"> http://www.parleys.com</a>): "How can we address the issue of evolving the [Java] platform, language, and libraries without breaking things?" <blockquote> Neal Gafter: "If you don't want to change the meaning of anything ever, you have no choice but to not do anything. The trick is to minimize the effect of the changes while enabling as much as possible. I think there's still a lot of room for adding functionality without breaking existing stuff..." </blockquote> <blockquote> Josh Bloch: "My view of what really happens is a little bit morbid. I think that languages and platforms age by getting larger and clunkier until they fall over of their own weight and die very very slowly, like over ... well, they're all still alive (though not many are programming Cobol anymore). I think it's a great thing, I really love it. I think it's marvelous. It's the cycle of birth, and growth, and death. I remember James saying to me [...] eight years ago 'It's really great when you get to hit the reset button every once and a while.'" </blockquote> <p>Josh may well be right. If so, we should place Java on life support and move our development to new languages such as Scala. The fork-join framework itself is an example of <a href="http://en.wikipedia.org/wiki/Higher-order_function">higher-order functional programming</a>, which <a href="http://www.parleys.com/display/PARLEYS/The+Closures+Controversy">Josh argues</a> is a style that <a href="http://gafter.blogspot.com/2007/12/what-flavor-of-closures.html#c8863950537789037629">we should neither encourage nor support in Java</a>. Is it really time to move on? <p>Personally, I believe rumors of Java's demise are greatly exaggerated. We should think of Java as a living language, and strive to eliminate much of the accidental complexity of Java programs. I believe it is worth adding support for closures and control abstraction, to reduce such complexity of both the sequential and concurrent aspects of our programs. At the same time, for completely new code bases, we should also consider (and continue to develop) newer languages such as Scala, which benefit from the lessons of Java.</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/4922325604477316744' onclick=''>40 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=2010-02-13T16:52:00-08:00&max-results=2&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=2008-01-11T17:16:00-08:00&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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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 expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </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 expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='posts'> <li><a href='https://gafter.blogspot.com/2008/08/java-closures-prototype-feature.html'>Java Closures Prototype Feature-Complete</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='posts'> <li><a href='https://gafter.blogspot.com/2008/03/closures-control-abstraction-method.html'>Closures: Control Abstraction, Method References, ...</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='posts'> <li><a href='https://gafter.blogspot.com/2008/02/closures-puzzler-neapolitan-ice-cream.html'>Closures Puzzler: Neapolitan Ice Cream</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2008/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='posts'> <li><a href='https://gafter.blogspot.com/2008/01/is-java-dying.html'>Is the Java Language Dying?</a></li> </ul> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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 collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://gafter.blogspot.com/2007/03/'> March </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> ►  </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'> </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/1455187647-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY61xi3-cesQ9OGC1_gN_Xe4h18sRg:1743534924503';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d7803021','//gafter.blogspot.com/2008/','7803021'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '7803021', 'title': 'Neal Gafter\x27s blog', 'url': 'https://gafter.blogspot.com/2008/', 'canonicalUrl': 'http://gafter.blogspot.com/2008/', '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/dddbdc640444f1d4', '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': '2008', 'pageTitle': 'Neal Gafter\x27s blog: 2008'}}, {'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/2008/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2008, 'rangeMessage': 'Showing posts from 2008'}}}]); _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/1425802369-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>