Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I have not followed the process and evolution of the Java 7 lambda proposal, I am not even sure of what the latest proposal wording is. Consider this as a rant/opinion rather than statements of truth. Also, I have not used Java for ages, so the syntax might be rusty and incorrect at places.</p> <p>First, what are lambdas to the Java language? Syntactic sugar. While in general lambdas enable code to create small function objects in place, that support was already preset --to some extent-- in the Java language through the use of inner classes.</p> <p>So how much better is the syntax of lambdas? Where does it outperform previous language constructs? Where could it be better?</p> <p>For starters, I dislike the fact that there are two available syntax for lambda functions (but this goes in the line of C#, so I guess my opinion is not widespread. I guess if we want to sugar coat, then <code>#(int x)(x*x)</code> is sweeter than <code>#(int x){ return x*x; }</code> even if the double syntax does not add anything else. I would have preferred the second syntax, more generic at the extra cost of writting <code>return</code> and <code>;</code> in the short versions.</p> <p>To be really useful, lambdas can take variables from the scope in where they are defined and from a <em>closure</em>. Being consistent with Inner classes, lambdas are restricted to <em>capturing</em> 'effectively final' variables. Consistency with the previous features of the language is a nice feature, but for sweetness, it would be nice to be able to capture variables that can be reassigned. For that purpose, they are considering that variables present in the context and annotated with <code>@Shared</code> will be captured <em>by-reference</em>, allowing assignments. To me this seems weird as how a lambda can use a variable is determined at the place of declaration of the variable rather than where the lambda is defined. A single variable could be used in more than one lambda and this forces the same behavior in all of them.</p> <p>Lambdas try to simulate actual function objects, but the proposal does not get completely there: to keep the parser simple, since up to now an identifier denotes either an object or a method that has been kept consistent and calling a lambda requires using a <code>!</code> after the lambda name: <code>#(int x)(x*x)!(5)</code> will return <code>25</code>. This brings a new syntax to use for lambdas that differ from the rest of the language, where <code>!</code> stands <em>somehow</em> as a synonim for <code>.execute</code> on a virtual generic interface <code>Lambda&lt;Result,Args...&gt;</code> but, why not make it complete?</p> <p>A new generic (virtual) interface <code>Lambda</code> could be created. It would have to be virtual as the interface is not a real interface, but a family of such: <code>Lambda&lt;Return&gt;</code>, <code>Lambda&lt;Return,Arg1&gt;</code>, <code>Lambda&lt;Return,Arg1,Arg2&gt;</code>... They could define a single execution method, which I would like to be like C++ <code>operator()</code>, but if that is a burden then any other name would be fine, embracing the <code>!</code> as a shortcut for the method execution:</p> <pre><code> interface Lambda&lt;R&gt; { R exec(); } interface Lambda&lt;R,A&gt; { R exec( A a ); } </code></pre> <p>Then the compiler need only translate <code>identifier!(args)</code> to <code>identifier.exec( args )</code>, which is simple. The translation of the lambda syntax would require the compiler to identify the proper interface being implemented and could be matched as:</p> <pre><code> #( int x )(x *x) // translated to new Lambda&lt;int,int&gt;{ int exec( int x ) { return x*x; } } </code></pre> <p>This would also allow users to define Inner classes that can be used as lambdas, in more complex situations. For example, if lambda function needed to capture a variable annotated as <code>@Shared</code> in a read-only manner, or maintain the state of the captured object at the place of capture, manual implementation of the Lambda would be available:</p> <pre><code> new Lambda&lt;int,int&gt;{ int value = context_value; int exec( int x ) { return x * context_value; } }; </code></pre> <p>In a manner similar to what the current Inner classes definition is, and thus being natural to current Java users. This could be used, for example, in a loop to generate multiplier lambdas:</p> <pre><code> Lambda&lt;int,int&gt; array[10] = new Lambda&lt;int,int&gt;[10](); for (int i = 0; i &lt; 10; ++i ) { array[i] = new Lambda&lt;int,int&gt;{ final int multiplier = i; int exec( int x ) { return x * multiplier; } }; } // note this is disallowed in the current proposal, as `i` is // not effectively final and as such cannot be 'captured'. Also // if `i` was marked @Shared, then all the lambdas would share // the same `i` as the loop and thus would produce the same // result: multiply by 10 --probably quite unexpectedly. // // I am aware that this can be rewritten as: // for (int ii = 0; ii &lt; 10; ++ii ) { final int i = ii; ... // // but that is not simplifying the system, just pushing the // complexity outside of the lambda. </code></pre> <p>This would allow usage of lambdas and methods that accept lambdas both with the new simple syntax: <code>#(int x){ return x*x; }</code> or with the more complex manual approach for specific cases where the sugar coating interferes with the intended semantics.</p> <p>Overall, I believe that the lambda proposal can be improved in different directions, that the way it adds syntactic sugar is a leaking abstraction (you have deal externally with issues that are particular to the lambda) and that by not providing a lower level interface it makes user code less readable in use cases that do not perfectly fit the simple use case. :</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload