A syntax option (function types versus arrays)
Rémi Forax
forax at univ-mlv.fr
Mon Mar 1 14:38:13 PST 2010
Le 01/03/2010 23:13, Alex Buckley a écrit :
> Thanks for recording a specific infix notation here, and the reasoning
> behind it. I am not opposed to infix notation, but I am opposed to
> saying that the type system will never allow arrays of function types.
> You and I did a JavaOne presentation in 2008 that majored on not
> restricting future evolution just because it helps with the syntax
> today. So can you comment on further grammar changes to allow
> parentheses round the function type:
>
> ((A throws X)->Y)[] y; // Array of function-typed values
>
> Alex
>
In that case, the inner parenthesis seems superfluous:
(A throws X -> Y)[] y;
Rémi
> Neal Gafter wrote:
>
>> *A Syntax Option for Project Lambda (Closures for
>> Java)<http://gafter.blogspot.com/2010/02/syntax-option-for-project-lambda.html>
>> *
>>
>> It was noted recently on the Project Lambda mailing
>> list<http://mail.openjdk.java.net/mailman/listinfo/lambda-dev>that
>> allowing arrays of function type would undermine the type system. The
>> reason for this is a combination of Java's covariant arrays, the natural
>> subtypes among function types (they are covariant on return type and
>> contravariant on argument types), exception checking, and the erasure
>> implementation of generics. We certainly can't remove covariant arrays or
>> checked exceptions, and removing the subtype relationship among function
>> types really reduces their utility. Unfortunately, it is almost certainly
>> too late to reify generics too. Although you can't have an array of function
>> type, there is no problem having, for example, an *ArrayList* of a function
>> type. So while we might prefer not to have this restriction, it won't be
>> much of a problem in practice.
>>
>> There are many ways in which arrays of function type would undermine the
>> type system, but to give you some flavor of the problem, the following is a
>> method written assuming that arrays of function type are allowed. This
>> method must fail in some way - either fail to compile, or throw a *
>> ClassCastException*, or an *ArrayStoreException*, or something. In all of
>> the implementations being considered, this method would throw *IOException*,
>> even though that isn't declared in the throws clause of the method. We have
>> undermined Java's exception checking without even a cast!
>>
>> *public** void main(String[] args) {*
>>
>> * #void()[] arrayOfFunction = new #void()[1];*
>>
>> * Object[] objectArray = arrayOfFunction;*
>>
>> * objectArray[0] = #(){ throw new IOException(); };*
>>
>> * arrayOfFunction[0].(); // invoke the function out of the array*
>>
>> *}*
>>
>> The realization that supporting arrays of function type would introduce a
>> loophole in the type system makes it possible to consider some very nice
>> syntax options that were previously eliminated because there was no
>> syntactic way to write an array of function type. But if we disallow arrays
>> of function type, those options can be considered.
>>
>> My favorite of the alternatives is based on this grammar
>>
>> *FunctionType*:
>>
>> *(* *TypeList*opt *Throws*opt *)* *->* *ResultType*
>>
>> *Expression*:
>>
>> *LambdaExpression*
>>
>> *LambdaExpression*:
>>
>> *(* *FormalParameterList*opt *)* *->* *Expression*
>>
>> A function type is written with the argument types between parentheses, then
>> a right arrow (dash greater-than), and then the result type.
>>
>> The most important distinction between this proposal and the existing draft
>> specification is that this proposal places the result type after the
>> argument types, instead of before. The benefits of its simplicity compared
>> to the current specification are most obvious when you combine function
>> types and lambdas with other features.
>>
>> Here is a simple example to show how the two proposals look. The example is
>> currying<http://en.wikipedia.org/wiki/Currying>. The following method takes
>> as a parameter a function of two arguments, and returns a function of one
>> argument that returns a function of one argument. Applying the resulting
>> function to one value, and then the result of that to another value, should
>> have the same effect as applying the original function to both values. To
>> make it interesting, we make the argument and result types generic, and we
>> allow the function to throw an exception.
>>
>> Using the currently proposed syntax for Project
>> Lambda<http://mail.openjdk.java.net/pipermail/lambda-dev/attachments/20100212/af8d2cc5/attachment-0001.txt>,
>> the code would look something like this:
>>
>> *static**<T,U,V,X extends Throwable>*
>>
>> *##V(U)(throws X)(T) curry(#V(T,U)(throws X) function) {*
>>
>> * return #(T t)(#(U u)(function.(t,u)));*
>>
>> *}*
>>
>> On the other hand, with the proposal described above it looks something like
>> this:
>>
>> *static**<T,U,V,X extends Throwable>*
>>
>> *(T)->(U throws X)->V curry((T,U throws X)->V function) {*
>>
>> * return (T t)->(U u)->function.(t,u);*
>>
>> *}*
>>
>> I've intentionally selected an example that uses the new features heavily,
>> so either may take a few moments of studying to understand. But I claim the
>> latter is much easier to follow than the former, even once you've become
>> familiar with the syntax.
>>
>> You can easily write a function that yields an array as its result
>>
>> *()-**>int[] arrayLambda = ()->new int[]{1, 2, 3};*
>>
>> With this proposed syntax there is no way to write an array of functions.
>> But that is exactly what we concluded could not be made to work within the
>> type system anyway.
>>
>>
>
More information about the lambda-dev
mailing list