Some people say that every programming language has its “complexity budget” which it can use to accomplish its purpose. But if the complexity budget is depleted, every minor change becomes increasingly complicated and hard to implement in a backward-compatible way.
After reading the current provisional syntax for Lambda (≙ Lambda expressions, exception transparency, defender methods and method references) from August 2010 I wonder if people at Oracle completely ignored Java’s complexity budget when considering such changes.
These are the questions I’m thinking about – some of them more about language design in general:
- Are the proposed additions comparable in complexity to approaches other languages chose?
- Is it generally possible to add such additions to a language and protecting the developer from the complexity of the implementation ?
- Are these additions a sign of reaching the end of the evolution of Java-as-a-language or is this expected when changing a language with a huge history?
- Have other languages taken a totally different approach at this point of language evolution?
Thanks!
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.
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.
So how much better is the syntax of lambdas? Where does it outperform
previous language constructs? Where could it be better?
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
#(int x)(x*x)is sweeter than#(int x){ return x*x; }even if thedouble syntax does not add anything else. I would have preferred the
second syntax, more generic at the extra cost of writting
returnand;in the short versions.To be really useful, lambdas can take variables from the scope in
where they are defined and from a closure. Being consistent with
Inner classes, lambdas are restricted to capturing ‘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
@Sharedwill be captured by-reference, allowingassignments. 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.
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
!after the lambdaname:
#(int x)(x*x)!(5)will return25. This brings a new syntaxto use for lambdas that differ from the rest of the language, where
!stands somehow as a synonim for.executeon a virtual genericinterface
Lambda<Result,Args...>but, why not make it complete?A new generic (virtual) interface
Lambdacould be created. It wouldhave to be virtual as the interface is not a real interface, but a
family of such:
Lambda<Return>,Lambda<Return,Arg1>,Lambda<Return,Arg1,Arg2>… They could define a single executionmethod, which I would like to be like C++
operator(), but if that isa burden then any other name would be fine, embracing the
!as ashortcut for the method execution:
Then the compiler need only translate
identifier!(args)toidentifier.exec( args ), which is simple. The translation of thelambda syntax would require the compiler to identify the proper
interface being implemented and could be matched as:
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
@Sharedin aread-only manner, or maintain the state of the captured object at the
place of capture, manual implementation of the Lambda would be
available:
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:
This would allow usage of lambdas and methods that accept lambdas both
with the new simple syntax:
#(int x){ return x*x; }or with the morecomplex manual approach for specific cases where the sugar coating
interferes with the intended semantics.
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.
: